From 4dee437028bef30079d134cee6810ca0868db992 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 17 Mar 2026 13:50:14 +0100 Subject: [PATCH 001/223] [wasm] Use wasm-gc signatures for wasm functions While this changes the IL to emit wasm-gc signatures for the functions, it doesn't yet actually allow using wasm-gc types in them. A few places (WasmDefineTable and WasmCallIndirect / WasmReturnCallIndirect) still need to be adapted to allow wasm-gc types before we can actually allow indexed wasm-gc types in function signatures. Bug: 445356784 Change-Id: I5715f584cfa5ee664f957a28e28bf80b6f3cdd9e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9115296 Commit-Queue: Matthias Liedtke Reviewed-by: Manos Koukoutos --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 22 ++++++++--- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 16 ++++---- Sources/Fuzzilli/FuzzIL/Instruction.swift | 14 ++----- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 12 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 16 ++++---- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 5 ++- Sources/Fuzzilli/Protobuf/operations.pb.swift | 38 ++++++------------- Sources/Fuzzilli/Protobuf/operations.proto | 6 +-- Tests/FuzzilliTests/MinimizerTest.swift | 12 +++--- 10 files changed, 69 insertions(+), 76 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 1448845f3..48d2a9cc2 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3495,11 +3495,14 @@ public class ProgramBuilder { private let b: ProgramBuilder let signature: WasmSignature let jsSignature: Signature + let signatureDef: Variable - public init(forBuilder b: ProgramBuilder, withSignature signature: WasmSignature) { + public init(forBuilder b: ProgramBuilder, signatureDef: Variable) { + assert(b.type(of: signatureDef).Is(.wasmTypeDef())) self.b = b - self.signature = signature + self.signature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature self.jsSignature = convertWasmSignatureToJsSignature(signature) + self.signatureDef = signatureDef } // Wasm Instructions @@ -4500,9 +4503,16 @@ public class ProgramBuilder { // TODO: distinguish between exported and non-exported functions @discardableResult public func addWasmFunction(with signature: WasmSignature, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { - let instr = b.emit(BeginWasmFunction(signature: signature)) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + return addWasmFunction(signature: signatureDef, body) + } + + @discardableResult + public func addWasmFunction(signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + let signatureType = b.type(of: signature).wasmFunctionSignatureDefSignature + let instr = b.emit(BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), withInputs: [signature]) let results = body(currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return b.emit(EndWasmFunction(signature: signature), withInputs: results).output + return b.emit(EndWasmFunction(outputCount: signatureType.outputTypes.count), withInputs: [signature] + results, types: [.wasmTypeDef()] + signatureType.outputTypes).output } @discardableResult @@ -5022,8 +5032,8 @@ public class ProgramBuilder { break case .wasmDefineTag(_): break - case .beginWasmFunction(let op): - activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) + case .beginWasmFunction(_): + activeWasmModule!.functions.append(WasmFunction(forBuilder: self, signatureDef: instr.input(0))) case .wasmBeginTry(_), .wasmEndTryDelegate(_), .wasmBeginTryDelegate(_), diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index ebe454e1d..5077ac26a 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1276,8 +1276,13 @@ public let WasmCodeGenerators: [CodeGenerator] = [ provides: [.wasmFunction] ) { b in let module = b.currentWasmModule + // TODO(mliedtke): Support index wasm-gc types in the signature. This requires the + // WasmDefineTable operation to track their types in a way that is compatible with + // wasm-gc types. Similarly, WasmCallIndirect and WasmReturnCallIndirect need to be + // adapted to use wasm-gc signatures. let functionSignature = b.randomWasmSignature() - b.emit(BeginWasmFunction(signature: functionSignature)) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: functionSignature) + b.emit(BeginWasmFunction(parameterCount: functionSignature.parameterTypes.count), withInputs: [signatureDef]) }, GeneratorStub( "WasmFunctionEndGenerator", @@ -1285,14 +1290,11 @@ public let WasmCodeGenerators: [CodeGenerator] = [ produces: [.wasmFunctionDef()] ) { b in let function = b.currentWasmFunction - let results = function.signature.outputTypes.map { - b.randomVariable(ofType: $0) ?? b.currentWasmFunction - .generateRandomWasmVar(ofType: $0)! - } + let results = function.signature.outputTypes.map(function.findOrGenerateWasmVar) b.emit( - EndWasmFunction(signature: function.signature), - withInputs: results) + EndWasmFunction(outputCount: results.count), + withInputs: [function.signatureDef] + results) }, ]), diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index bc48ed434..e558bb6fb 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1373,13 +1373,11 @@ extension Instruction: ProtobufConvertible { $0.wasmDropDataSegment = Fuzzilli_Protobuf_WasmDropDataSegment() case .beginWasmFunction(let op): $0.beginWasmFunction = Fuzzilli_Protobuf_BeginWasmFunction.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) } case .endWasmFunction(let op): $0.endWasmFunction = Fuzzilli_Protobuf_EndWasmFunction.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.outputCount) } case .wasmBeginBlock(let op): $0.wasmBeginBlock = Fuzzilli_Protobuf_WasmBeginBlock.with { @@ -2441,13 +2439,9 @@ extension Instruction: ProtobufConvertible { case .wasmDropDataSegment(_): op = WasmDropDataSegment() case .beginWasmFunction(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = BeginWasmFunction(signature: parameters => outputs) + op = BeginWasmFunction(parameterCount: Int(p.parameterCount)) case .endWasmFunction(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = EndWasmFunction(signature: parameters => outputs) + op = EndWasmFunction(outputCount: Int(p.outputCount)) case .wasmBeginBlock(let p): op = WasmBeginBlock(parameterCount: Int(p.parameterCount)) case .wasmEndBlock(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index da7acc4a1..51ddac359 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -812,11 +812,13 @@ public struct JSTyper: Analyzer { let definingInstruction = defUseAnalyzer.definition(of: instr.input(1)) // Here we query the typer for the signature of the instruction as that is the correct "JS" Signature instead of taking the call-site specific converted wasm signature. dynamicObjectGroupManager.addWasmFunction(withSignature: type(of: instr.input(1)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(1)) - case .beginWasmFunction(let op): - wasmTypeBeginBlock(instr, op.signature) - case .endWasmFunction(let op): - setType(of: instr.output, to: .wasmFunctionDef(op.signature)) - dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(op.signature), forDefinition: instr, forVariable: instr.output) + case .beginWasmFunction(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) + case .endWasmFunction(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + setType(of: instr.output, to: .wasmFunctionDef(signature)) + dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), forDefinition: instr, forVariable: instr.output) case .wasmSelect(_): setType(of: instr.output, to: type(of: instr.input(0))) case .wasmBeginBlock(_): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 15c9c6533..55d3b16c0 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1552,22 +1552,22 @@ final class WasmReassign: WasmOperation { final class BeginWasmFunction: WasmOperation { override var opcode: Opcode { .beginWasmFunction(self) } - public let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInnerOutputs: 1 + signature.parameterTypes.count, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) + init(parameterCount: Int) { + super.init(numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) } + + var parameterCount: Int { numInnerOutputs - 1 } } final class EndWasmFunction: WasmOperation { override var opcode: Opcode { .endWasmFunction(self) } - let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.outputTypes.count, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + init(outputCount: Int) { + super.init(numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) } + + var outputCount: Int { numInputs - 1 } } /// This class is used to indicate nops in the wasm world, this makes handling of minimization much easier. diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 09c706802..fd6ce0df9 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -830,9 +830,9 @@ public class FuzzILLifter: Lifter { // Wasm Instructions - case .beginWasmFunction(let op): + case .beginWasmFunction(_): // TODO(cffsmith): do this properly? - w.emit("BeginWasmFunction (\(op.signature)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit("BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") w.increaseIndentionLevel() case .endWasmFunction: diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index d27d6d24a..5a3f391dc 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1287,8 +1287,9 @@ public class WasmLifter { // Just analyze the instruction but do nothing else here. // This lets the typer know that we can skip this instruction without breaking any analysis. break - case .beginWasmFunction(let op): - let functionInfo = FunctionInfo(op.signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) + case .beginWasmFunction(_): + let signature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let functionInfo = FunctionInfo(signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) self.exports.append(.function(functionInfo)) // Set the current active function as we are *actively* in it. currentFunction = functionInfo diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 8c92cbfd5..f3ff5d557 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4180,9 +4180,7 @@ public struct Fuzzilli_Protobuf_BeginWasmFunction: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var parameterCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -4194,9 +4192,7 @@ public struct Fuzzilli_Protobuf_EndWasmFunction: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -11689,7 +11685,7 @@ extension Fuzzilli_Protobuf_WasmILType: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginWasmFunction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11697,26 +11693,21 @@ extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProto // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 2) + if self.parameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.parameterCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_BeginWasmFunction, rhs: Fuzzilli_Protobuf_BeginWasmFunction) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -11724,7 +11715,7 @@ extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProto extension Fuzzilli_Protobuf_EndWasmFunction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EndWasmFunction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}outputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11732,26 +11723,21 @@ extension Fuzzilli_Protobuf_EndWasmFunction: SwiftProtobuf.Message, SwiftProtobu // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 2) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_EndWasmFunction, rhs: Fuzzilli_Protobuf_EndWasmFunction) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 11eec98eb..a67da4b89 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -929,13 +929,11 @@ message WasmILType { } message BeginWasmFunction { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message EndWasmFunction { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 outputCount = 1; } message WasmJsCall { diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 74b14a786..b874ca9c6 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1592,7 +1592,7 @@ class MinimizerTests: XCTestCase { } catchAllBody: { label in function.wasmReturn(function.consti64(-1)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1602,7 +1602,7 @@ class MinimizerTests: XCTestCase { function.wasmBuildLegacyTryVoid { label in function.wasmReturn(function.consti64(42)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } } @@ -1628,7 +1628,7 @@ class MinimizerTests: XCTestCase { function.wasmReturn(val) }), (tag: irrelevantTag, body: { _, _, _ in })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1642,7 +1642,7 @@ class MinimizerTests: XCTestCase { }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmReturn(function.consti64(42)) })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } } @@ -1659,7 +1659,7 @@ class MinimizerTests: XCTestCase { evaluator.nextInstructionIsImportant(in: b) function.wasmReturn(val) }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1667,7 +1667,7 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmReturn(function.consti64(42)) - return [function.consti32(-1)] + return [function.consti64(-1)] } } } From 376c31fe638bde932737651480d56a7f0e724602 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 20 Mar 2026 09:01:12 +0100 Subject: [PATCH 002/223] Fix an unused-variable warning Change-Id: I4e2111aca7b7619584bffe9d008c60f55da18999 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9122916 Auto-Submit: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 51ddac359..e9a469a67 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -802,7 +802,7 @@ public struct JSTyper: Analyzer { let isMemory64 = type(of: instr.input(0)).wasmMemoryType?.isMemory64 ?? false registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: isMemory64 ? .wasmi64 : .wasmi32) - case .wasmJsCall(let op): + case .wasmJsCall(_): let wasmSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature let sigOutputTypes = wasmSignature.outputTypes assert(sigOutputTypes.count < 2, "multi-return js calls are not supported") From 794dda87980fe673391bec0c7ce170c14a5a1aa9 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 19 Mar 2026 12:41:18 +0100 Subject: [PATCH 003/223] Refactoring: Merge static and instance class member instructions This simplifies and reduces a lot of code and prepares adding support for more kinds of class members without exploding the number of instructions due to the additional factor 2 for static and instance members. Concretely this merges instructions for all members (properties, elements and methods) that have a static and non-static (instance) variant. The static bit is represented by a variable in the instruction. This was also tested locally with and without this change, both with large number for class-related code generators. Both versions resulted in similar correctness stats without any crashes. Bug: 446634535 Change-Id: I57b3261e202dffeb57704d0040b2a8d02b50a9e6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9094176 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 135 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 65 +- Sources/Fuzzilli/Compiler/Compiler.swift | 80 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 200 +- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 173 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 227 +- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 42 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 30 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 147 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 152 +- .../Fuzzilli/Minimization/BlockReducer.swift | 15 +- .../Minimization/InliningReducer.swift | 30 +- .../Fuzzilli/Mutators/OperationMutator.swift | 57 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 844 ++------ Sources/Fuzzilli/Protobuf/operations.proto | 93 +- Sources/Fuzzilli/Protobuf/program.pb.swift | 1926 +++++++---------- Sources/Fuzzilli/Protobuf/program.proto | 600 +++-- 17 files changed, 1720 insertions(+), 3096 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 48d2a9cc2..aea8a1c5f 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2649,60 +2649,61 @@ public class ProgramBuilder { b.emit(EndClassConstructor()) } + public func addInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddInstanceProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddInstanceElement(index: index, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddInstanceComputedProperty(hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassInstanceMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) } public func addInstanceComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassInstanceComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), withInputs: [name]) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) } public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceGetter(propertyName: name)) + let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: false)) body(instr.innerOutput) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassGetter()) } public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceSetter(propertyName: name)) + let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) - b.emit(EndClassInstanceSetter()) + b.emit(EndClassSetter()) } public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddStaticProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddStaticElement(index: index, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddStaticComputedProperty(hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticInitializer(_ body: (Variable) -> ()) { @@ -2713,52 +2714,52 @@ public class ProgramBuilder { public func addStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassStaticMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) } public func addStaticComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassStaticComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), withInputs: [name]) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) } public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassStaticGetter(propertyName: name)) + let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: true)) body(instr.innerOutput) - b.emit(EndClassStaticGetter()) + b.emit(EndClassGetter()) } public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassStaticSetter(propertyName: name)) + let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) - b.emit(EndClassStaticSetter()) + b.emit(EndClassSetter()) } public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateInstanceProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addPrivateInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateInstanceMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) - b.emit(EndClassPrivateInstanceMethod()) + b.emit(EndClassPrivateMethod()) } public func addPrivateStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateStaticProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addPrivateStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateStaticMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) - b.emit(EndClassPrivateStaticMethod()) + b.emit(EndClassPrivateMethod()) } } @@ -4963,41 +4964,51 @@ public class ProgramBuilder { activeClassDefinitions.push(ClassDefinition(in: self, isDerived: op.hasSuperclass)) case .beginClassConstructor: activeClassDefinitions.top.hasConstructor = true - case .classAddInstanceProperty(let op): - activeClassDefinitions.top.instanceProperties.append(op.propertyName) - case .classAddInstanceElement(let op): - activeClassDefinitions.top.instanceElements.append(op.index) - case .classAddInstanceComputedProperty: - activeClassDefinitions.top.instanceComputedProperties.append(instr.input(0)) - case .beginClassInstanceMethod(let op): - activeClassDefinitions.top.instanceMethods.append(op.methodName) - case .beginClassInstanceComputedMethod: - activeClassDefinitions.top.instanceComputedMethods.append(instr.input(0)) - case .beginClassInstanceGetter(let op): - activeClassDefinitions.top.instanceGetters.append(op.propertyName) - case .beginClassInstanceSetter(let op): - activeClassDefinitions.top.instanceSetters.append(op.propertyName) - case .classAddStaticProperty(let op): - activeClassDefinitions.top.staticProperties.append(op.propertyName) - case .classAddStaticElement(let op): - activeClassDefinitions.top.staticElements.append(op.index) - case .classAddStaticComputedProperty: - activeClassDefinitions.top.staticComputedProperties.append(instr.input(0)) - case .beginClassStaticMethod(let op): - activeClassDefinitions.top.staticMethods.append(op.methodName) - case .beginClassStaticComputedMethod: - activeClassDefinitions.top.staticComputedMethods.append(instr.input(0)) - case .beginClassStaticGetter(let op): - activeClassDefinitions.top.staticGetters.append(op.propertyName) - case .beginClassStaticSetter(let op): - activeClassDefinitions.top.staticSetters.append(op.propertyName) - case .classAddPrivateInstanceProperty(let op): - activeClassDefinitions.top.privateProperties.append(op.propertyName) - case .beginClassPrivateInstanceMethod(let op): - activeClassDefinitions.top.privateMethods.append(op.methodName) - case .classAddPrivateStaticProperty(let op): + case .classAddProperty(let op): + if op.isStatic { + activeClassDefinitions.top.staticProperties.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceProperties.append(op.propertyName) + } + case .classAddElement(let op): + if op.isStatic { + activeClassDefinitions.top.staticElements.append(op.index) + } else { + activeClassDefinitions.top.instanceElements.append(op.index) + } + case .classAddComputedProperty(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedProperties.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedProperties.append(instr.input(0)) + } + case .beginClassMethod(let op): + if op.isStatic { + activeClassDefinitions.top.staticMethods.append(op.methodName) + } else { + activeClassDefinitions.top.instanceMethods.append(op.methodName) + } + case .beginClassComputedMethod(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedMethods.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedMethods.append(instr.input(0)) + } + case .beginClassGetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticGetters.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceGetters.append(op.propertyName) + } + case .beginClassSetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticSetters.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceSetters.append(op.propertyName) + } + case .classAddPrivateProperty(let op): activeClassDefinitions.top.privateProperties.append(op.propertyName) - case .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): activeClassDefinitions.top.privateMethods.append(op.methodName) case .beginClassStaticInitializer: break diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 3783c67c5..5a3bed0eb 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -100,8 +100,9 @@ func disposableClassVariableGeneratorStubs( let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), withInputs: [symbol]) }, GeneratorStub( @@ -110,7 +111,7 @@ func disposableClassVariableGeneratorStubs( provides: [.classDefinition] ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) }, GeneratorStub( "DisposableClassDefinitionEndGenerator", @@ -967,16 +968,17 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: false)) }, GeneratorStub( "ClassInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) }, ]), @@ -1001,8 +1003,9 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), withInputs: [methodName]) }, GeneratorStub( @@ -1010,7 +1013,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -1026,13 +1029,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties + b.currentClassDefinition.instanceGetters) - b.emit(BeginClassInstanceGetter(propertyName: propertyName)) + b.emit(BeginClassGetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( "ClassInstanceGetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.doReturn(b.randomJsVariable()) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassGetter()) }, ]), @@ -1048,13 +1051,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties + b.currentClassDefinition.instanceSetters) - b.emit(BeginClassInstanceSetter(propertyName: propertyName)) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( "ClassInstanceSetterEndGenerator", inContext: .single([.javascript, .method, .subroutine, .classMethod]) ) { b in - b.emit(EndClassInstanceSetter()) + b.emit(EndClassSetter()) }, ]), @@ -1136,9 +1139,10 @@ public let CodeGenerators: [CodeGenerator] = [ b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassStaticMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: true)) }, GeneratorStub( @@ -1146,7 +1150,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .classMethod, .subroutine, .method]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) }, ]), @@ -1171,8 +1175,9 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassStaticComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: true), withInputs: [methodName]) }, GeneratorStub( @@ -1180,7 +1185,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -1196,14 +1201,14 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties + b.currentClassDefinition.staticGetters) - b.emit(BeginClassStaticGetter(propertyName: propertyName)) + b.emit(BeginClassGetter(propertyName: propertyName, isStatic: true)) }, GeneratorStub( "ClassStaticGetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.doReturn(b.randomJsVariable()) - b.emit(EndClassStaticGetter()) + b.emit(EndClassGetter()) }, ]), @@ -1219,13 +1224,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties + b.currentClassDefinition.staticSetters) - b.emit(BeginClassStaticSetter(propertyName: propertyName)) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: true)) }, GeneratorStub( "ClassStaticSetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.emit(EndClassStaticSetter()) + b.emit(EndClassSetter()) }, ]), @@ -1254,16 +1259,17 @@ public let CodeGenerators: [CodeGenerator] = [ notIn: b.currentClassDefinition.privateFields) let parameters = b.randomParameters() b.emit( - BeginClassPrivateInstanceMethod( + BeginClassPrivateMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: false)) }, GeneratorStub( "ClassPrivateInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassPrivateInstanceMethod()) + b.emit(EndClassPrivateMethod()) }, ]), @@ -1291,16 +1297,17 @@ public let CodeGenerators: [CodeGenerator] = [ notIn: b.currentClassDefinition.privateFields) let parameters = b.randomParameters() b.emit( - BeginClassPrivateStaticMethod( + BeginClassPrivateMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: true)) }, GeneratorStub( "ClassPrivateStaticMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassPrivateStaticMethod()) + b.emit(EndClassPrivateMethod()) }, ]), diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 0f2f4f0bb..d8a4def6e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -117,24 +117,12 @@ public class JavaScriptCompiler { var inputs = [Variable]() switch key { case .name(let name): - if property.isStatic { - op = ClassAddStaticProperty(propertyName: name, hasValue: property.hasValue) - } else { - op = ClassAddInstanceProperty(propertyName: name, hasValue: property.hasValue) - } + op = ClassAddProperty(propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic) case .index(let index): - if property.isStatic { - op = ClassAddStaticElement(index: index, hasValue: property.hasValue) - } else { - op = ClassAddInstanceElement(index: index, hasValue: property.hasValue) - } + op = ClassAddElement(index: index, hasValue: property.hasValue, isStatic: property.isStatic) case .expression: inputs.append(computedKeys.removeLast()) - if property.isStatic { - op = ClassAddStaticComputedProperty(hasValue: property.hasValue) - } else { - op = ClassAddInstanceComputedProperty(hasValue: property.hasValue) - } + op = ClassAddComputedProperty(hasValue: property.hasValue, isStatic: property.isStatic) } if property.hasValue { inputs.append(propertyValues.removeLast()) @@ -165,23 +153,11 @@ public class JavaScriptCompiler { } switch key { case .name(let name): - if method.isStatic { - head = emit(BeginClassStaticMethod(methodName: name, parameters: parameters)) - } else { - head = emit(BeginClassInstanceMethod(methodName: name, parameters: parameters)) - } + head = emit(BeginClassMethod(methodName: name, parameters: parameters, isStatic: method.isStatic)) case .index(let index): - if method.isStatic { - head = emit(BeginClassStaticMethod(methodName: String(index), parameters: parameters)) - } else { - head = emit(BeginClassInstanceMethod(methodName: String(index), parameters: parameters)) - } + head = emit(BeginClassMethod(methodName: String(index), parameters: parameters, isStatic: method.isStatic)) case .expression: - if method.isStatic { - head = emit(BeginClassStaticComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) - } else { - head = emit(BeginClassInstanceComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) - } + head = emit(BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -195,32 +171,15 @@ public class JavaScriptCompiler { switch key { case .name: - if method.isStatic { - emit(EndClassStaticMethod()) - } else { - emit(EndClassInstanceMethod()) - } + emit(EndClassMethod()) case .index: - if method.isStatic { - emit(EndClassStaticMethod()) - } else { - emit(EndClassInstanceMethod()) - } + emit(EndClassMethod()) case .expression: - if method.isStatic { - emit(EndClassStaticComputedMethod()) - } else { - emit(EndClassInstanceComputedMethod()) - } + emit(EndClassComputedMethod()) } case .getter(let getter): - let head: Instruction - if getter.isStatic { - head = emit(BeginClassStaticGetter(propertyName: getter.name)) - } else { - head = emit(BeginClassInstanceGetter(propertyName: getter.name)) - } + let head = emit(BeginClassGetter(propertyName: getter.name, isStatic: getter.isStatic)) try enterNewScope { map("this", to: head.innerOutput) @@ -229,19 +188,10 @@ public class JavaScriptCompiler { } } - if getter.isStatic { - emit(EndClassStaticGetter()) - } else { - emit(EndClassInstanceGetter()) - } + emit(EndClassGetter()) case .setter(let setter): - let head: Instruction - if setter.isStatic { - head = emit(BeginClassStaticSetter(propertyName: setter.name)) - } else { - head = emit(BeginClassInstanceSetter(propertyName: setter.name)) - } + let head = emit(BeginClassSetter(propertyName: setter.name, isStatic: setter.isStatic)) try enterNewScope { var parameters = head.innerOutputs @@ -253,11 +203,7 @@ public class JavaScriptCompiler { } } - if setter.isStatic { - emit(EndClassStaticSetter()) - } else { - emit(EndClassInstanceSetter()) - } + emit(EndClassSetter()) case .staticInitializer(let staticInitializer): let head = emit(BeginClassStaticInitializer()) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index e558bb6fb..2ea23a453 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -613,100 +613,70 @@ extension Instruction: ProtobufConvertible { $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { $0.parameters = convertParameters(op.parameters) } case .endClassConstructor: $0.endClassConstructor = Fuzzilli_Protobuf_EndClassConstructor() - case .classAddInstanceProperty(let op): - $0.classAddInstanceProperty = Fuzzilli_Protobuf_ClassAddInstanceProperty.with { + case .classAddProperty(let op): + $0.classAddProperty = Fuzzilli_Protobuf_ClassAddProperty.with { $0.propertyName = op.propertyName $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddInstanceElement(let op): - $0.classAddInstanceElement = Fuzzilli_Protobuf_ClassAddInstanceElement.with { + case .classAddElement(let op): + $0.classAddElement = Fuzzilli_Protobuf_ClassAddElement.with { $0.index = op.index $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddInstanceComputedProperty(let op): - $0.classAddInstanceComputedProperty = Fuzzilli_Protobuf_ClassAddInstanceComputedProperty.with { $0.hasValue_p = op.hasValue } - case .beginClassInstanceMethod(let op): - $0.beginClassInstanceMethod = Fuzzilli_Protobuf_BeginClassInstanceMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) + case .classAddComputedProperty(let op): + $0.classAddComputedProperty = Fuzzilli_Protobuf_ClassAddComputedProperty.with { + $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .endClassInstanceMethod: - $0.endClassInstanceMethod = Fuzzilli_Protobuf_EndClassInstanceMethod() - case .beginClassInstanceComputedMethod(let op): - $0.beginClassInstanceComputedMethod = Fuzzilli_Protobuf_BeginClassInstanceComputedMethod.with { + case .endClassMethod: + $0.endClassMethod = Fuzzilli_Protobuf_EndClassMethod() + case .beginClassComputedMethod(let op): + $0.beginClassComputedMethod = Fuzzilli_Protobuf_BeginClassComputedMethod.with { $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassInstanceComputedMethod: - $0.endClassInstanceComputedMethod = Fuzzilli_Protobuf_EndClassInstanceComputedMethod() - case .beginClassInstanceGetter(let op): - $0.beginClassInstanceGetter = Fuzzilli_Protobuf_BeginClassInstanceGetter.with { $0.propertyName = op.propertyName } - case .endClassInstanceGetter: - $0.endClassInstanceGetter = Fuzzilli_Protobuf_EndClassInstanceGetter() - case .beginClassInstanceSetter(let op): - $0.beginClassInstanceSetter = Fuzzilli_Protobuf_BeginClassInstanceSetter.with { $0.propertyName = op.propertyName } - case .endClassInstanceSetter: - $0.endClassInstanceSetter = Fuzzilli_Protobuf_EndClassInstanceSetter() - case .classAddStaticProperty(let op): - $0.classAddStaticProperty = Fuzzilli_Protobuf_ClassAddStaticProperty.with { + case .endClassComputedMethod: + $0.endClassComputedMethod = Fuzzilli_Protobuf_EndClassComputedMethod() + case .beginClassGetter(let op): + $0.beginClassGetter = Fuzzilli_Protobuf_BeginClassGetter.with { $0.propertyName = op.propertyName - $0.hasValue_p = op.hasValue - } - case .classAddStaticElement(let op): - $0.classAddStaticElement = Fuzzilli_Protobuf_ClassAddStaticElement.with { - $0.index = op.index - $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddStaticComputedProperty(let op): - $0.classAddStaticComputedProperty = Fuzzilli_Protobuf_ClassAddStaticComputedProperty.with { $0.hasValue_p = op.hasValue } - case .beginClassStaticInitializer: - $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() - case .endClassStaticInitializer: - $0.endClassStaticInitializer = Fuzzilli_Protobuf_EndClassStaticInitializer() - case .beginClassStaticMethod(let op): - $0.beginClassStaticMethod = Fuzzilli_Protobuf_BeginClassStaticMethod.with { + case .beginClassPrivateMethod(let op): + $0.beginClassPrivateMethod = Fuzzilli_Protobuf_BeginClassPrivateMethod.with { $0.methodName = op.methodName $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassStaticMethod: - $0.endClassStaticMethod = Fuzzilli_Protobuf_EndClassStaticMethod() - case .beginClassStaticComputedMethod(let op): - $0.beginClassStaticComputedMethod = Fuzzilli_Protobuf_BeginClassStaticComputedMethod.with { + case .endClassPrivateMethod: + $0.endClassPrivateMethod = Fuzzilli_Protobuf_EndClassPrivateMethod() + case .beginClassMethod(let op): + $0.beginClassMethod = Fuzzilli_Protobuf_BeginClassMethod.with { + $0.methodName = op.methodName $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassStaticComputedMethod: - $0.endClassStaticComputedMethod = Fuzzilli_Protobuf_EndClassStaticComputedMethod() - case .beginClassStaticGetter(let op): - $0.beginClassStaticGetter = Fuzzilli_Protobuf_BeginClassStaticGetter.with { $0.propertyName = op.propertyName } - case .endClassStaticGetter: - $0.endClassStaticGetter = Fuzzilli_Protobuf_EndClassStaticGetter() - case .beginClassStaticSetter(let op): - $0.beginClassStaticSetter = Fuzzilli_Protobuf_BeginClassStaticSetter.with { $0.propertyName = op.propertyName } - case .endClassStaticSetter: - $0.endClassStaticSetter = Fuzzilli_Protobuf_EndClassStaticSetter() - case .classAddPrivateInstanceProperty(let op): - $0.classAddPrivateInstanceProperty = Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty.with { + case .endClassGetter: + $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() + case .beginClassSetter(let op): + $0.beginClassSetter = Fuzzilli_Protobuf_BeginClassSetter.with { $0.propertyName = op.propertyName - $0.hasValue_p = op.hasValue - } - case .beginClassPrivateInstanceMethod(let op): - $0.beginClassPrivateInstanceMethod = Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassPrivateInstanceMethod: - $0.endClassPrivateInstanceMethod = Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - case .classAddPrivateStaticProperty(let op): - $0.classAddPrivateStaticProperty = Fuzzilli_Protobuf_ClassAddPrivateStaticProperty.with { + case .endClassSetter: + $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() + case .beginClassStaticInitializer: + $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() + case .endClassStaticInitializer: + $0.endClassStaticInitializer = Fuzzilli_Protobuf_EndClassStaticInitializer() + case .classAddPrivateProperty(let op): + $0.classAddPrivateProperty = Fuzzilli_Protobuf_ClassAddPrivateProperty.with { $0.propertyName = op.propertyName $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .beginClassPrivateStaticMethod(let op): - $0.beginClassPrivateStaticMethod = Fuzzilli_Protobuf_BeginClassPrivateStaticMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) - } - case .endClassPrivateStaticMethod: - $0.endClassPrivateStaticMethod = Fuzzilli_Protobuf_EndClassPrivateStaticMethod() case .endClassDefinition: $0.endClassDefinition = Fuzzilli_Protobuf_EndClassDefinition() case .createArray: @@ -1907,66 +1877,38 @@ extension Instruction: ProtobufConvertible { op = BeginClassConstructor(parameters: convertParameters(p.parameters)) case .endClassConstructor: op = EndClassConstructor() - case .classAddInstanceProperty(let p): - op = ClassAddInstanceProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .classAddInstanceElement(let p): - op = ClassAddInstanceElement(index: p.index, hasValue: p.hasValue_p) - case .classAddInstanceComputedProperty(let p): - op = ClassAddInstanceComputedProperty(hasValue: p.hasValue_p) - case .beginClassInstanceMethod(let p): - op = BeginClassInstanceMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassInstanceMethod: - op = EndClassInstanceMethod() - case .beginClassInstanceComputedMethod(let p): - op = BeginClassInstanceComputedMethod(parameters: convertParameters(p.parameters)) - case .endClassInstanceComputedMethod: - op = EndClassInstanceComputedMethod() - case .beginClassInstanceGetter(let p): - op = BeginClassInstanceGetter(propertyName: p.propertyName) - case .endClassInstanceGetter: - op = EndClassInstanceGetter() - case .beginClassInstanceSetter(let p): - op = BeginClassInstanceSetter(propertyName: p.propertyName) - case .endClassInstanceSetter: - op = EndClassInstanceSetter() - case .classAddStaticProperty(let p): - op = ClassAddStaticProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .classAddStaticElement(let p): - op = ClassAddStaticElement(index: p.index, hasValue: p.hasValue_p) - case .classAddStaticComputedProperty(let p): - op = ClassAddStaticComputedProperty(hasValue: p.hasValue_p) + case .classAddProperty(let p): + op = ClassAddProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .classAddElement(let p): + op = ClassAddElement(index: p.index, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .classAddComputedProperty(let p): + op = ClassAddComputedProperty(hasValue: p.hasValue_p, isStatic: p.isStatic) + case .beginClassMethod(let p): + op = BeginClassMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassMethod: + op = EndClassMethod() + case .beginClassComputedMethod(let p): + op = BeginClassComputedMethod(parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassComputedMethod: + op = EndClassComputedMethod() + case .beginClassGetter(let p): + op = BeginClassGetter(propertyName: p.propertyName, isStatic: p.isStatic) + case .endClassGetter: + op = EndClassGetter() + case .beginClassSetter(let p): + op = BeginClassSetter(propertyName: p.propertyName, isStatic: p.isStatic) + case .endClassSetter: + op = EndClassSetter() case .beginClassStaticInitializer: op = BeginClassStaticInitializer() case .endClassStaticInitializer: op = EndClassStaticInitializer() - case .beginClassStaticMethod(let p): - op = BeginClassStaticMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassStaticMethod: - op = EndClassStaticMethod() - case .beginClassStaticComputedMethod(let p): - op = BeginClassStaticComputedMethod(parameters: convertParameters(p.parameters)) - case .endClassStaticComputedMethod: - op = EndClassStaticComputedMethod() - case .beginClassStaticGetter(let p): - op = BeginClassStaticGetter(propertyName: p.propertyName) - case .endClassStaticGetter: - op = EndClassStaticGetter() - case .beginClassStaticSetter(let p): - op = BeginClassStaticSetter(propertyName: p.propertyName) - case .endClassStaticSetter: - op = EndClassStaticSetter() - case .classAddPrivateInstanceProperty(let p): - op = ClassAddPrivateInstanceProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .beginClassPrivateInstanceMethod(let p): - op = BeginClassPrivateInstanceMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassPrivateInstanceMethod: - op = EndClassPrivateInstanceMethod() - case .classAddPrivateStaticProperty(let p): - op = ClassAddPrivateStaticProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .beginClassPrivateStaticMethod(let p): - op = BeginClassPrivateStaticMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassPrivateStaticMethod: - op = EndClassPrivateStaticMethod() + case .classAddPrivateProperty(let p): + op = ClassAddPrivateProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .beginClassPrivateMethod(let p): + op = BeginClassPrivateMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassPrivateMethod: + op = EndClassPrivateMethod() case .endClassDefinition: op = EndClassDefinition() case .createArray: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index e9a469a67..584572320 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1295,16 +1295,11 @@ public struct JSTyper: Analyzer { .beginAsyncGeneratorFunction, .beginConstructor, .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, + .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, @@ -1319,16 +1314,11 @@ public struct JSTyper: Analyzer { .endAsyncGeneratorFunction, .endConstructor, .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter, + .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). // @@ -1363,30 +1353,30 @@ public struct JSTyper: Analyzer { // TODO(cffsmith): this is probably the wrong place to do this. // Update the dynamic object group to correctly reflect the signature of objects of this type. switch instr.op.opcode { - case .endClassInstanceMethod(_): - assert(begin.op is BeginClassInstanceMethod) - let beginOp = begin.op as! BeginClassInstanceMethod - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) - case .endClassInstanceGetter(_): - assert(begin.op is BeginClassInstanceGetter) - let beginOp = begin.op as! BeginClassInstanceGetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassInstanceSetter(_): - assert(begin.op is BeginClassInstanceSetter) - let beginOp = begin.op as! BeginClassInstanceSetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassStaticGetter(_): - assert(begin.op is BeginClassStaticGetter) - let beginOp = begin.op as! BeginClassStaticGetter - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassStaticMethod(_): - assert(begin.op is BeginClassStaticMethod) - let beginOp = begin.op as! BeginClassStaticMethod - dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) - case .endClassStaticSetter(_): - assert(begin.op is BeginClassStaticSetter) - let beginOp = begin.op as! BeginClassStaticSetter - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + case .endClassMethod(_): + assert(begin.op is BeginClassMethod) + let beginOp = begin.op as! BeginClassMethod + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + } else { + dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + } + case .endClassGetter(_): + assert(begin.op is BeginClassGetter) + let beginOp = begin.op as! BeginClassGetter + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } else { + dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } + case .endClassSetter(_): + assert(begin.op is BeginClassSetter) + let beginOp = begin.op as! BeginClassSetter + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } else { + dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } case .endObjectLiteralMethod(_): assert(begin.op is BeginObjectLiteralMethod) let beginOp = begin.op as! BeginObjectLiteralMethod @@ -1600,74 +1590,71 @@ public struct JSTyper: Analyzer { processParameterDeclarations(instr.innerOutputs(1...), parameters: parameters) dynamicObjectGroupManager.setConstructorParameters(parameters: parameters) - case .classAddInstanceProperty(let op): - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) - - case .beginClassInstanceMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) - - case .beginClassInstanceComputedMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - - case .beginClassInstanceGetter(let op): - // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - assert(instr.numInnerOutputs == 1) - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - - case .beginClassInstanceSetter(let op): - // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - - case .classAddStaticProperty(let op): - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + case .classAddProperty(let op): + if op.isStatic { + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + } else { + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + } case .beginClassStaticInitializer: // The first inner output is the explicit |this| set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) - case .beginClassStaticMethod(let op): + case .beginClassMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) - case .beginClassStaticComputedMethod(let op): + case .beginClassComputedMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - case .beginClassStaticGetter(let op): + case .beginClassGetter(let op): // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) - assert(instr.numInnerOutputs == 1) - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + assert(instr.numInnerOutputs == 1) + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + assert(instr.numInnerOutputs == 1) + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + } - case .beginClassStaticSetter(let op): + case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + } assert(instr.numInnerOutputs == 2) processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) - case .beginClassPrivateInstanceMethod(let op): + case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - - case .beginClassPrivateStaticMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .createArray, diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index bc87ecb2a..f47db65d8 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -696,145 +696,119 @@ final class EndClassConstructor: EndAnySubroutine { override var opcode: Opcode { .endClassConstructor(self) } } -final class ClassAddInstanceProperty: JsOperation { - override var opcode: Opcode { .classAddInstanceProperty(self) } +final class ClassAddProperty: JsOperation { + override var opcode: Opcode { .classAddProperty(self) } let propertyName: String var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(propertyName: String, hasValue: Bool) { + init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } -final class ClassAddInstanceElement: JsOperation { - override var opcode: Opcode { .classAddInstanceElement(self) } +final class ClassAddElement: JsOperation { + override var opcode: Opcode { .classAddElement(self) } let index: Int64 var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(index: Int64, hasValue: Bool) { + init(index: Int64, hasValue: Bool, isStatic: Bool) { self.index = index + self.isStatic = isStatic super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } -final class ClassAddInstanceComputedProperty: JsOperation { - override var opcode: Opcode { .classAddInstanceComputedProperty(self) } +final class ClassAddComputedProperty: JsOperation { + override var opcode: Opcode { .classAddComputedProperty(self) } var hasValue: Bool { return numInputs == 2 } + let isStatic: Bool - init(hasValue: Bool) { + init(hasValue: Bool, isStatic: Bool) { + self.isStatic = isStatic super.init(numInputs: hasValue ? 2 : 1, requiredContext: .classDefinition) } } -final class BeginClassInstanceMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceMethod(self) } +final class BeginClassMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassMethod(self) } let methodName: String + let isStatic: Bool - init(methodName: String, parameters: Parameters) { + init(methodName: String, parameters: Parameters, isStatic: Bool) { self.methodName = methodName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceMethod(self) } +final class EndClassMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassMethod(self) } } -final class BeginClassInstanceComputedMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceComputedMethod(self) } +final class BeginClassComputedMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedMethod(self) } + let isStatic: Bool - init(parameters: Parameters) { + init(parameters: Parameters, isStatic: Bool) { + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceComputedMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceComputedMethod(self) } +final class EndClassComputedMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedMethod(self) } } -final class BeginClassInstanceGetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceGetter(self) } +final class BeginClassGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassGetter(self) } let propertyName: String + let isStatic: Bool - init(propertyName: String) { + init(propertyName: String, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceGetter: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceGetter(self) } +final class EndClassGetter: EndAnySubroutine { + override var opcode: Opcode { .endClassGetter(self) } } -final class BeginClassInstanceSetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceSetter(self) } +final class BeginClassSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassSetter(self) } let propertyName: String + let isStatic: Bool - init(propertyName: String) { + init(propertyName: String, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceSetter: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceSetter(self) } -} - -final class ClassAddStaticProperty: JsOperation { - override var opcode: Opcode { .classAddStaticProperty(self) } - - let propertyName: String - var hasValue: Bool { - return numInputs == 1 - } - - init(propertyName: String, hasValue: Bool) { - self.propertyName = propertyName - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) - } -} - -final class ClassAddStaticElement: JsOperation { - override var opcode: Opcode { .classAddStaticElement(self) } - - let index: Int64 - var hasValue: Bool { - return numInputs == 1 - } - - init(index: Int64, hasValue: Bool) { - self.index = index - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) - } -} - -final class ClassAddStaticComputedProperty: JsOperation { - override var opcode: Opcode { .classAddStaticComputedProperty(self) } - - var hasValue: Bool { - return numInputs == 2 - } - - init(hasValue: Bool) { - super.init(numInputs: hasValue ? 2 : 1, requiredContext: .classDefinition) - } +final class EndClassSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassSetter(self) } } final class BeginClassStaticInitializer: JsOperation { @@ -855,130 +829,41 @@ final class EndClassStaticInitializer: JsOperation { } } -final class BeginClassStaticMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticMethod(self) } - - let methodName: String - - init(methodName: String, parameters: Parameters) { - self.methodName = methodName - // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticMethod(self) } -} - -final class BeginClassStaticComputedMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticComputedMethod(self) } - - init(parameters: Parameters) { - // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticComputedMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticComputedMethod(self) } -} - -final class BeginClassStaticGetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticGetter(self) } - - let propertyName: String - - init(propertyName: String) { - self.propertyName = propertyName - // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticGetter: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticGetter(self) } -} - -final class BeginClassStaticSetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticSetter(self) } - - let propertyName: String - - init(propertyName: String) { - self.propertyName = propertyName - // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticSetter: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticSetter(self) } -} - -final class ClassAddPrivateInstanceProperty: JsOperation { - override var opcode: Opcode { .classAddPrivateInstanceProperty(self) } +final class ClassAddPrivateProperty: JsOperation { + override var opcode: Opcode { .classAddPrivateProperty(self) } let propertyName: String var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(propertyName: String, hasValue: Bool) { + init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // We currently don't want to change the names of private properties since that has a good chance of making // following code _syntactically_ incorrect (if it uses them) because an undeclared private field is accessed. super.init(numInputs: hasValue ? 1 : 0, requiredContext: .classDefinition) } } -final class BeginClassPrivateInstanceMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassPrivateInstanceMethod(self) } - - let methodName: String - - init(methodName: String, parameters: Parameters) { - self.methodName = methodName - // First inner output is the explicit |this| parameter. - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassPrivateInstanceMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassPrivateInstanceMethod(self) } -} - -final class ClassAddPrivateStaticProperty: JsOperation { - override var opcode: Opcode { .classAddPrivateStaticProperty(self) } - - let propertyName: String - var hasValue: Bool { - return numInputs == 1 - } - - init(propertyName: String, hasValue: Bool) { - self.propertyName = propertyName - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. - super.init(numInputs: hasValue ? 1 : 0, requiredContext: .classDefinition) - } -} - -final class BeginClassPrivateStaticMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassPrivateStaticMethod(self) } +final class BeginClassPrivateMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassPrivateMethod(self) } let methodName: String + let isStatic: Bool - init(methodName: String, parameters: Parameters) { + init(methodName: String, parameters: Parameters, isStatic: Bool) { self.methodName = methodName + self.isStatic = isStatic // First inner output is the explicit |this| parameter. - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. + // See comment in ClassAddPrivateProperty for why this operation isn't mutable. super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassPrivateStaticMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassPrivateStaticMethod(self) } +final class EndClassPrivateMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassPrivateMethod(self) } } final class EndClassDefinition: JsOperation { diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index b50931649..4918d7d14 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -62,36 +62,22 @@ enum Opcode { case beginClassDefinition(BeginClassDefinition) case beginClassConstructor(BeginClassConstructor) case endClassConstructor(EndClassConstructor) - case classAddInstanceProperty(ClassAddInstanceProperty) - case classAddInstanceElement(ClassAddInstanceElement) - case classAddInstanceComputedProperty(ClassAddInstanceComputedProperty) - case beginClassInstanceMethod(BeginClassInstanceMethod) - case endClassInstanceMethod(EndClassInstanceMethod) - case beginClassInstanceComputedMethod(BeginClassInstanceComputedMethod) - case endClassInstanceComputedMethod(EndClassInstanceComputedMethod) - case beginClassInstanceGetter(BeginClassInstanceGetter) - case endClassInstanceGetter(EndClassInstanceGetter) - case beginClassInstanceSetter(BeginClassInstanceSetter) - case endClassInstanceSetter(EndClassInstanceSetter) - case classAddStaticProperty(ClassAddStaticProperty) - case classAddStaticElement(ClassAddStaticElement) - case classAddStaticComputedProperty(ClassAddStaticComputedProperty) + case classAddProperty(ClassAddProperty) + case classAddElement(ClassAddElement) + case classAddComputedProperty(ClassAddComputedProperty) + case beginClassMethod(BeginClassMethod) + case endClassMethod(EndClassMethod) + case beginClassComputedMethod(BeginClassComputedMethod) + case endClassComputedMethod(EndClassComputedMethod) + case beginClassGetter(BeginClassGetter) + case endClassGetter(EndClassGetter) + case beginClassSetter(BeginClassSetter) + case endClassSetter(EndClassSetter) case beginClassStaticInitializer(BeginClassStaticInitializer) case endClassStaticInitializer(EndClassStaticInitializer) - case beginClassStaticMethod(BeginClassStaticMethod) - case endClassStaticMethod(EndClassStaticMethod) - case beginClassStaticComputedMethod(BeginClassStaticComputedMethod) - case endClassStaticComputedMethod(EndClassStaticComputedMethod) - case beginClassStaticGetter(BeginClassStaticGetter) - case endClassStaticGetter(EndClassStaticGetter) - case beginClassStaticSetter(BeginClassStaticSetter) - case endClassStaticSetter(EndClassStaticSetter) - case classAddPrivateInstanceProperty(ClassAddPrivateInstanceProperty) - case beginClassPrivateInstanceMethod(BeginClassPrivateInstanceMethod) - case endClassPrivateInstanceMethod(EndClassPrivateInstanceMethod) - case classAddPrivateStaticProperty(ClassAddPrivateStaticProperty) - case beginClassPrivateStaticMethod(BeginClassPrivateStaticMethod) - case endClassPrivateStaticMethod(EndClassPrivateStaticMethod) + case classAddPrivateProperty(ClassAddPrivateProperty) + case beginClassPrivateMethod(BeginClassPrivateMethod) + case endClassPrivateMethod(EndClassPrivateMethod) case endClassDefinition(EndClassDefinition) case createArray(CreateArray) case createIntArray(CreateIntArray) diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index 968003082..ab4af0339 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -144,28 +144,18 @@ extension Operation { return endOp is EndClassDefinition case .beginClassConstructor: return endOp is EndClassConstructor - case .beginClassInstanceMethod: - return endOp is EndClassInstanceMethod - case .beginClassInstanceComputedMethod: - return endOp is EndClassInstanceComputedMethod - case .beginClassInstanceGetter: - return endOp is EndClassInstanceGetter - case .beginClassInstanceSetter: - return endOp is EndClassInstanceSetter + case .beginClassMethod: + return endOp is EndClassMethod + case .beginClassComputedMethod: + return endOp is EndClassComputedMethod + case .beginClassGetter: + return endOp is EndClassGetter + case .beginClassSetter: + return endOp is EndClassSetter case .beginClassStaticInitializer: return endOp is EndClassStaticInitializer - case .beginClassStaticMethod: - return endOp is EndClassStaticMethod - case .beginClassStaticComputedMethod: - return endOp is EndClassStaticComputedMethod - case .beginClassStaticGetter: - return endOp is EndClassStaticGetter - case .beginClassStaticSetter: - return endOp is EndClassStaticSetter - case .beginClassPrivateInstanceMethod: - return endOp is EndClassPrivateInstanceMethod - case .beginClassPrivateStaticMethod: - return endOp is EndClassPrivateStaticMethod + case .beginClassPrivateMethod: + return endOp is EndClassPrivateMethod case .beginPlainFunction: return endOp is EndPlainFunction case .beginArrowFunction: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index fd6ce0df9..7b94c258e 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -167,83 +167,69 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassConstructor") - case .classAddInstanceProperty(let op): + case .classAddProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceProperty '\(op.propertyName)' \(input(0))") + w.emit("ClassAddProperty '\(maybeStatic)\(op.propertyName)' \(input(0))") } else { - w.emit("ClassAddInstanceProperty '\(op.propertyName)'") + w.emit("ClassAddProperty '\(maybeStatic)\(op.propertyName)'") } - case .classAddInstanceElement(let op): + case .classAddElement(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceElement '\(op.index)' \(input(0))") + w.emit("ClassAddElement '\(maybeStatic)\(op.index)' \(input(0))") } else { - w.emit("ClassAddInstanceElement '\(op.index)'") + w.emit("ClassAddElement '\(maybeStatic)\(op.index)'") } - case .classAddInstanceComputedProperty(let op): + case .classAddComputedProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceComputedProperty \(input(0)) \(input(1))") + w.emit("ClassAddComputedProperty \(maybeStatic)\(input(0)) \(input(1))") } else { - w.emit("ClassAddInstanceComputedProperty \(input(0))") + w.emit("ClassAddComputedProperty \(maybeStatic)\(input(0))") } - case .beginClassInstanceMethod(let op): + case .beginClassMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceMethod '\(op.methodName)' -> \(params)") + w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceMethod: + case .endClassMethod: w.decreaseIndentionLevel() - w.emit("EndClassInstanceMethod") + w.emit("EndClassMethod") - case .beginClassInstanceComputedMethod: + case .beginClassComputedMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceComputedMethod \(input(0)) -> \(params)") + w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0)) -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceComputedMethod: + case .endClassComputedMethod: w.decreaseIndentionLevel() - w.emit("EndClassInstanceComputedMethod") + w.emit("EndClassComputedMethod") - case .beginClassInstanceGetter(let op): + case .beginClassGetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceGetter `\(op.propertyName)` -> \(params)") + w.emit("BeginClassGetter '\(maybeStatic)\(op.propertyName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceGetter: + case .endClassGetter: w.decreaseIndentionLevel() - w.emit("EndClassInstanceGetter") + w.emit("EndClassGetter") - case .beginClassInstanceSetter(let op): + case .beginClassSetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceSetter `\(op.propertyName)` -> \(params)") + w.emit("BeginClassSetter '\(maybeStatic)\(op.propertyName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceSetter: + case .endClassSetter: w.decreaseIndentionLevel() - w.emit("EndClassInstanceSetter") - - case .classAddStaticProperty(let op): - if op.hasValue { - w.emit("ClassAddStaticProperty '\(op.propertyName)' \(input(0))") - } else { - w.emit("ClassAddStaticProperty '\(op.propertyName)'") - } - - case .classAddStaticElement(let op): - if op.hasValue { - w.emit("ClassAddStaticElement '\(op.index)' \(input(0))") - } else { - w.emit("ClassAddStaticElement '\(op.index)'") - } - - case .classAddStaticComputedProperty(let op): - if op.hasValue { - w.emit("ClassAddStaticComputedProperty \(input(0)) \(input(1))") - } else { - w.emit("ClassAddStaticComputedProperty \(input(0))") - } + w.emit("EndClassSetter") case .beginClassStaticInitializer: w.emit("BeginClassStaticInitializer -> \(lift(instr.innerOutput))") @@ -253,74 +239,23 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassStaticInitializer") - case .beginClassStaticMethod(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticMethod '\(op.methodName)' -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticMethod: - w.decreaseIndentionLevel() - w.emit("EndClassStaticMethod") - - case .beginClassStaticComputedMethod: - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticComputedMethod \(input(0)) -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticComputedMethod: - w.decreaseIndentionLevel() - w.emit("EndClassStaticComputedMethod") - - case .beginClassStaticGetter(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticGetter `\(op.propertyName)` -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticGetter: - w.decreaseIndentionLevel() - w.emit("EndClassStaticGetter") - - case .beginClassStaticSetter(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticSetter `\(op.propertyName)` -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticSetter: - w.decreaseIndentionLevel() - w.emit("EndClassStaticSetter") - - case .classAddPrivateInstanceProperty(let op): + case .classAddPrivateProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddPrivateInstanceProperty '\(op.propertyName)' \(input(0))") + w.emit("ClassAddPrivateProperty '\(maybeStatic)\(op.propertyName)' \(input(0))") } else { - w.emit("ClassAddPrivateInstanceProperty '\(op.propertyName)'") + w.emit("ClassAddPrivateProperty '\(maybeStatic)\(op.propertyName)'") } - case .beginClassPrivateInstanceMethod(let op): + case .beginClassPrivateMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateInstanceMethod '\(op.methodName)' -> \(params)") + w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)' -> \(params)") w.increaseIndentionLevel() - case .endClassPrivateInstanceMethod: + case .endClassPrivateMethod: w.decreaseIndentionLevel() - w.emit("EndClassPrivateInstanceMethod") - - case .classAddPrivateStaticProperty(let op): - if op.hasValue { - w.emit("ClassAddPrivateStaticProperty '\(op.propertyName)' \(input(0))") - } else { - w.emit("ClassAddPrivateStaticProperty '\(op.propertyName)'") - } - - case .beginClassPrivateStaticMethod(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateStaticMethod '\(op.methodName)' -> \(params)") - w.increaseIndentionLevel() - - case .endClassPrivateStaticMethod: - w.decreaseIndentionLevel() - w.emit("EndClassPrivateStaticMethod") - + w.emit("EndClassPrivateMethod") case .endClassDefinition: w.decreaseIndentionLevel() w.emit("EndClassDefinition") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 8b523ed25..680e77f47 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -496,179 +496,107 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") - case .classAddInstanceProperty(let op): + case .classAddProperty(let op): let PROPERTY = op.propertyName + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("\(PROPERTY) = \(VALUE);") + w.emit("\(staticStr)\(PROPERTY) = \(VALUE);") } else { - w.emit("\(PROPERTY);") + w.emit("\(staticStr)\(PROPERTY);") } - case .classAddInstanceElement(let op): + case .classAddElement(let op): let INDEX = op.index < 0 ? "[\(op.index)]" : String(op.index) + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("\(INDEX) = \(VALUE);") + w.emit("\(staticStr)\(INDEX) = \(VALUE);") } else { - w.emit("\(INDEX);") + w.emit("\(staticStr)\(INDEX);") } - case .classAddInstanceComputedProperty(let op): + case .classAddComputedProperty(let op): let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(1) - w.emit("[\(PROPERTY)] = \(VALUE);") + w.emit("\(staticStr)[\(PROPERTY)] = \(VALUE);") } else { - w.emit("[\(PROPERTY)];") + w.emit("\(staticStr)[\(PROPERTY)];") } - case .beginClassInstanceMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) - w.emit("\(METHOD)(\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceComputedMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = input(0) - w.emit("[\(METHOD)](\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceGetter(let op): - let PROPERTY = op.propertyName - w.emit("get \(PROPERTY)() {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceSetter(let op): - assert(instr.numInnerOutputs == 2) - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName - w.emit("set \(PROPERTY)(\(PARAMS)) {") + case .beginClassStaticInitializer: + w.emit("static {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter: + case .endClassStaticInitializer: w.leaveCurrentBlock() w.emit("}") - case .classAddStaticProperty(let op): - let PROPERTY = op.propertyName - if op.hasValue { - let VALUE = input(0) - w.emit("static \(PROPERTY) = \(VALUE);") - } else { - w.emit("static \(PROPERTY);") - } - - case .classAddStaticElement(let op): - let INDEX = op.index < 0 ? "[\(op.index)]" : String(op.index) - if op.hasValue { - let VALUE = input(0) - w.emit("static \(INDEX) = \(VALUE);") - } else { - w.emit("static \(INDEX);") - } - - case .classAddStaticComputedProperty(let op): - let PROPERTY = input(0) - if op.hasValue { - let VALUE = input(1) - w.emit("static [\(PROPERTY)] = \(VALUE);") - } else { - w.emit("static [\(PROPERTY)];") - } - - case .beginClassStaticInitializer: - w.emit("static {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassStaticMethod(let op): + case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) - w.emit("static \(METHOD)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticComputedMethod(let op): + case .beginClassComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = input(0) - w.emit("static [\(METHOD)](\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)[\(METHOD)](\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticGetter(let op): - assert(instr.numInnerOutputs == 1) + case .beginClassGetter(let op): let PROPERTY = op.propertyName - w.emit("static get \(PROPERTY)() {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)get \(PROPERTY)() {") w.enterNewBlock() - bindVariableToThis(instr.innerOutput) + bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticSetter(let op): + case .beginClassSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let PROPERTY = op.propertyName - w.emit("static set \(PROPERTY)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)set \(PROPERTY)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassStaticInitializer, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter: + case .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter: w.leaveCurrentBlock() w.emit("}") - case .classAddPrivateInstanceProperty(let op): - let PROPERTY = op.propertyName - if op.hasValue { - let VALUE = input(0) - w.emit("#\(PROPERTY) = \(VALUE);") - } else { - w.emit("#\(PROPERTY);") - } - - case .beginClassPrivateInstanceMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = op.methodName - w.emit("#\(METHOD)(\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .classAddPrivateStaticProperty(let op): + case .classAddPrivateProperty(let op): let PROPERTY = op.propertyName + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("static #\(PROPERTY) = \(VALUE);") + w.emit("\(staticStr)#\(PROPERTY) = \(VALUE);") } else { - w.emit("static #\(PROPERTY);") + w.emit("\(staticStr)#\(PROPERTY);") } - case .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = op.methodName - w.emit("static #\(METHOD)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)#\(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + case .endClassPrivateMethod: w.leaveCurrentBlock() w.emit("}") diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index aec2abf3c..af5ca9fbc 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -37,17 +37,12 @@ struct BlockReducer: Reducer { reduceClassDefinition(group.block(0), with: helper) case .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 9704f81d9..7f6cf85d5 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -61,17 +61,12 @@ struct InliningReducer: Reducer { .beginObjectLiteralGetter, .beginObjectLiteralSetter, .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, .endArrowFunction, @@ -85,17 +80,12 @@ struct InliningReducer: Reducer { .endObjectLiteralGetter, .endObjectLiteralSetter, .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter, .endClassStaticInitializer, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 2e73465e0..d87ef0d23 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -124,26 +124,16 @@ public class OperationMutator: BaseInstructionMutator { newOp = BeginObjectLiteralGetter(propertyName: b.randomPropertyName()) case .beginObjectLiteralSetter: newOp = BeginObjectLiteralSetter(propertyName: b.randomPropertyName()) - case .classAddInstanceProperty(let op): - newOp = ClassAddInstanceProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue) - case .classAddInstanceElement(let op): - newOp = ClassAddInstanceElement(index: b.randomIndex(), hasValue: op.hasValue) - case .beginClassInstanceMethod(let op): - newOp = BeginClassInstanceMethod(methodName: b.randomMethodName(), parameters: op.parameters) - case .beginClassInstanceGetter: - newOp = BeginClassInstanceGetter(propertyName: b.randomPropertyName()) - case .beginClassInstanceSetter: - newOp = BeginClassInstanceSetter(propertyName: b.randomPropertyName()) - case .classAddStaticProperty(let op): - newOp = ClassAddStaticProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue) - case .classAddStaticElement(let op): - newOp = ClassAddStaticElement(index: b.randomIndex(), hasValue: op.hasValue) - case .beginClassStaticMethod(let op): - newOp = BeginClassStaticMethod(methodName: b.randomMethodName(), parameters: op.parameters) - case .beginClassStaticGetter: - newOp = BeginClassStaticGetter(propertyName: b.randomPropertyName()) - case .beginClassStaticSetter: - newOp = BeginClassStaticSetter(propertyName: b.randomPropertyName()) + case .classAddProperty(let op): + newOp = ClassAddProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue, isStatic: op.isStatic) + case .classAddElement(let op): + newOp = ClassAddElement(index: b.randomIndex(), hasValue: op.hasValue, isStatic: op.isStatic) + case .beginClassMethod(let op): + newOp = BeginClassMethod(methodName: b.randomMethodName(), parameters: op.parameters, isStatic: op.isStatic) + case .beginClassGetter(let op): + newOp = BeginClassGetter(propertyName: b.randomPropertyName(), isStatic: op.isStatic) + case .beginClassSetter(let op): + newOp = BeginClassSetter(propertyName: b.randomPropertyName(), isStatic: op.isStatic) case .createIntArray: var values = [Int64]() for _ in 0..(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7050,6 +6873,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, Swi switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7062,20 +6886,24 @@ extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, Swi if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceProperty, rhs: Fuzzilli_Protobuf_ClassAddInstanceProperty) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddProperty, rhs: Fuzzilli_Protobuf_ClassAddProperty) -> Bool { if lhs.propertyName != rhs.propertyName {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddInstanceElement" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddElement" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7085,6 +6913,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, Swif switch fieldNumber { case 1: try { try decoder.decodeSingularInt64Field(value: &self.index) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7097,20 +6926,24 @@ extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, Swif if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceElement, rhs: Fuzzilli_Protobuf_ClassAddInstanceElement) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddElement, rhs: Fuzzilli_Protobuf_ClassAddElement) -> Bool { if lhs.index != rhs.index {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddInstanceComputedProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddComputedProperty" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7119,6 +6952,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Mess // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7128,19 +6962,23 @@ extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Mess if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddComputedProperty) -> Bool { if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") +extension Fuzzilli_Protobuf_BeginClassMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7150,6 +6988,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, Swi switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7166,19 +7005,23 @@ extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, Swi try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceMethod, rhs: Fuzzilli_Protobuf_BeginClassInstanceMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassMethod, rhs: Fuzzilli_Protobuf_BeginClassMethod) -> Bool { if lhs.methodName != rhs.methodName {return false} if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceMethod" +extension Fuzzilli_Protobuf_EndClassMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7190,15 +7033,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceMethod: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceMethod, rhs: Fuzzilli_Protobuf_EndClassInstanceMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassMethod, rhs: Fuzzilli_Protobuf_EndClassMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0") +extension Fuzzilli_Protobuf_BeginClassComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7207,6 +7050,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Mess // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7220,18 +7064,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Mess try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) } }() + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassComputedMethod) -> Bool { if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceComputedMethod" +extension Fuzzilli_Protobuf_EndClassComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7243,15 +7091,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceComputedMethod: SwiftProtobuf.Messag try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceComputedMethod, rhs: Fuzzilli_Protobuf_EndClassInstanceComputedMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedMethod, rhs: Fuzzilli_Protobuf_EndClassComputedMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") +extension Fuzzilli_Protobuf_BeginClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7260,6 +7108,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, Swi // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7269,18 +7118,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, Swi if !self.propertyName.isEmpty { try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceGetter, rhs: Fuzzilli_Protobuf_BeginClassInstanceGetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassGetter, rhs: Fuzzilli_Protobuf_BeginClassGetter) -> Bool { if lhs.propertyName != rhs.propertyName {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceGetter" +extension Fuzzilli_Protobuf_EndClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassGetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7292,15 +7145,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceGetter: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceGetter, rhs: Fuzzilli_Protobuf_EndClassInstanceGetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassGetter, rhs: Fuzzilli_Protobuf_EndClassGetter) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") +extension Fuzzilli_Protobuf_BeginClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7309,6 +7162,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7318,18 +7172,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi if !self.propertyName.isEmpty { try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceSetter, rhs: Fuzzilli_Protobuf_BeginClassInstanceSetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassSetter, rhs: Fuzzilli_Protobuf_BeginClassSetter) -> Bool { if lhs.propertyName != rhs.propertyName {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceSetter" +extension Fuzzilli_Protobuf_EndClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7341,50 +7199,53 @@ extension Fuzzilli_Protobuf_EndClassInstanceSetter: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceSetter, rhs: Fuzzilli_Protobuf_EndClassInstanceSetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassSetter, rhs: Fuzzilli_Protobuf_EndClassSetter) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddStaticProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticInitializer, rhs: Fuzzilli_Protobuf_BeginClassStaticInitializer) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassStaticInitializer" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticInitializer, rhs: Fuzzilli_Protobuf_EndClassStaticInitializer) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticElement" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddPrivateProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateProperty" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7392,34 +7253,39 @@ extension Fuzzilli_Protobuf_ClassAddStaticElement: SwiftProtobuf.Message, SwiftP // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularInt64Field(value: &self.index) }() + case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } } public func traverse(visitor: inout V) throws { - if self.index != 0 { - try visitor.visitSingularInt64Field(value: self.index, fieldNumber: 1) + if !self.propertyName.isEmpty { + try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticElement, rhs: Fuzzilli_Protobuf_ClassAddStaticElement) -> Bool { - if lhs.index != rhs.index {return false} + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateProperty) -> Bool { + if lhs.propertyName != rhs.propertyName {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticComputedProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_BeginClassPrivateMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7427,320 +7293,9 @@ extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: SwiftProtobuf.Messag // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddStaticComputedProperty) -> Bool { - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticInitializer, rhs: Fuzzilli_Protobuf_BeginClassStaticInitializer) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticInitializer" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticInitializer, rhs: Fuzzilli_Protobuf_EndClassStaticInitializer) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.methodName.isEmpty { - try visitor.visitSingularStringField(value: self.methodName, fieldNumber: 1) - } - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticMethod, rhs: Fuzzilli_Protobuf_BeginClassStaticMethod) -> Bool { - if lhs.methodName != rhs.methodName {return false} - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticMethod, rhs: Fuzzilli_Protobuf_EndClassStaticMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassStaticComputedMethod) -> Bool { - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticComputedMethod, rhs: Fuzzilli_Protobuf_EndClassStaticComputedMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticGetter, rhs: Fuzzilli_Protobuf_BeginClassStaticGetter) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticGetter, rhs: Fuzzilli_Protobuf_EndClassStaticGetter) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticSetter, rhs: Fuzzilli_Protobuf_BeginClassStaticSetter) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticSetter, rhs: Fuzzilli_Protobuf_EndClassStaticSetter) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateInstanceProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7757,112 +7312,23 @@ extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: SwiftProtobuf.Messa try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod) -> Bool { - if lhs.methodName != rhs.methodName {return false} - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassPrivateInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateStaticProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.methodName.isEmpty { - try visitor.visitSingularStringField(value: self.methodName, fieldNumber: 1) - } - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateMethod) -> Bool { if lhs.methodName != rhs.methodName {return false} if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassPrivateStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateStaticMethod" +extension Fuzzilli_Protobuf_EndClassPrivateMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7874,7 +7340,7 @@ extension Fuzzilli_Protobuf_EndClassPrivateStaticMethod: SwiftProtobuf.Message, try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateStaticMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateStaticMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index a67da4b89..1be3ee744 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -129,61 +129,54 @@ message BeginClassConstructor { message EndClassConstructor { } -message ClassAddInstanceProperty { +message ClassAddProperty { string propertyName = 1; bool hasValue = 2; + bool is_static = 3; } -message ClassAddInstanceElement { +message ClassAddElement { int64 index = 1; bool hasValue = 2; + bool is_static = 3; } -message ClassAddInstanceComputedProperty { +message ClassAddComputedProperty { bool hasValue = 1; + bool is_static = 2; } -message BeginClassInstanceMethod { +message BeginClassMethod { string methodName = 1; Parameters parameters = 2; + bool is_static = 3; } -message EndClassInstanceMethod { +message EndClassMethod { } -message BeginClassInstanceComputedMethod { +message BeginClassComputedMethod { Parameters parameters = 1; + bool is_static = 2; } -message EndClassInstanceComputedMethod { +message EndClassComputedMethod { } -message BeginClassInstanceGetter { +message BeginClassGetter { string propertyName = 1; + bool is_static = 2; } -message EndClassInstanceGetter { +message EndClassGetter { } -message BeginClassInstanceSetter { +message BeginClassSetter { string propertyName = 1; + bool is_static = 2; } -message EndClassInstanceSetter { -} - -message ClassAddStaticProperty { - string propertyName = 1; - bool hasValue = 2; -} - -message ClassAddStaticElement { - int64 index = 1; - bool hasValue = 2; -} - -message ClassAddStaticComputedProperty { - bool hasValue = 1; +message EndClassSetter { } message BeginClassStaticInitializer { @@ -192,59 +185,19 @@ message BeginClassStaticInitializer { message EndClassStaticInitializer { } -message BeginClassStaticMethod { - string methodName = 1; - Parameters parameters = 2; -} - -message EndClassStaticMethod { -} - -message BeginClassStaticComputedMethod { - Parameters parameters = 1; -} - -message EndClassStaticComputedMethod { -} - -message BeginClassStaticGetter { - string propertyName = 1; -} - -message EndClassStaticGetter { -} - -message BeginClassStaticSetter { - string propertyName = 1; -} - -message EndClassStaticSetter { -} - -message ClassAddPrivateInstanceProperty { - string propertyName = 1; - bool hasValue = 2; -} - -message BeginClassPrivateInstanceMethod { - string methodName = 1; - Parameters parameters = 2; -} - -message EndClassPrivateInstanceMethod { -} - -message ClassAddPrivateStaticProperty { +message ClassAddPrivateProperty { string propertyName = 1; bool hasValue = 2; + bool is_static = 3; } -message BeginClassPrivateStaticMethod { +message BeginClassPrivateMethod { string methodName = 1; Parameters parameters = 2; + bool is_static = 3; } -message EndClassPrivateStaticMethod { +message EndClassPrivateMethod { } message EndClassDefinition { diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 2b13319ad..9684e4e6c 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -313,116 +313,92 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassConstructor(newValue)} } - public var classAddInstanceProperty: Fuzzilli_Protobuf_ClassAddInstanceProperty { + public var classAddProperty: Fuzzilli_Protobuf_ClassAddProperty { get { - if case .classAddInstanceProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceProperty() + if case .classAddProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddProperty() } - set {operation = .classAddInstanceProperty(newValue)} + set {operation = .classAddProperty(newValue)} } - public var classAddInstanceElement: Fuzzilli_Protobuf_ClassAddInstanceElement { + public var classAddElement: Fuzzilli_Protobuf_ClassAddElement { get { - if case .classAddInstanceElement(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceElement() + if case .classAddElement(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddElement() } - set {operation = .classAddInstanceElement(newValue)} + set {operation = .classAddElement(newValue)} } - public var classAddInstanceComputedProperty: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty { + public var classAddComputedProperty: Fuzzilli_Protobuf_ClassAddComputedProperty { get { - if case .classAddInstanceComputedProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceComputedProperty() + if case .classAddComputedProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddComputedProperty() } - set {operation = .classAddInstanceComputedProperty(newValue)} + set {operation = .classAddComputedProperty(newValue)} } - public var beginClassInstanceMethod: Fuzzilli_Protobuf_BeginClassInstanceMethod { + public var beginClassMethod: Fuzzilli_Protobuf_BeginClassMethod { get { - if case .beginClassInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceMethod() + if case .beginClassMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassMethod() } - set {operation = .beginClassInstanceMethod(newValue)} + set {operation = .beginClassMethod(newValue)} } - public var endClassInstanceMethod: Fuzzilli_Protobuf_EndClassInstanceMethod { + public var endClassMethod: Fuzzilli_Protobuf_EndClassMethod { get { - if case .endClassInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceMethod() + if case .endClassMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassMethod() } - set {operation = .endClassInstanceMethod(newValue)} + set {operation = .endClassMethod(newValue)} } - public var beginClassInstanceComputedMethod: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod { + public var beginClassComputedMethod: Fuzzilli_Protobuf_BeginClassComputedMethod { get { - if case .beginClassInstanceComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceComputedMethod() + if case .beginClassComputedMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedMethod() } - set {operation = .beginClassInstanceComputedMethod(newValue)} + set {operation = .beginClassComputedMethod(newValue)} } - public var endClassInstanceComputedMethod: Fuzzilli_Protobuf_EndClassInstanceComputedMethod { + public var endClassComputedMethod: Fuzzilli_Protobuf_EndClassComputedMethod { get { - if case .endClassInstanceComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceComputedMethod() + if case .endClassComputedMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedMethod() } - set {operation = .endClassInstanceComputedMethod(newValue)} + set {operation = .endClassComputedMethod(newValue)} } - public var beginClassInstanceGetter: Fuzzilli_Protobuf_BeginClassInstanceGetter { + public var beginClassGetter: Fuzzilli_Protobuf_BeginClassGetter { get { - if case .beginClassInstanceGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceGetter() + if case .beginClassGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassGetter() } - set {operation = .beginClassInstanceGetter(newValue)} + set {operation = .beginClassGetter(newValue)} } - public var endClassInstanceGetter: Fuzzilli_Protobuf_EndClassInstanceGetter { + public var endClassGetter: Fuzzilli_Protobuf_EndClassGetter { get { - if case .endClassInstanceGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceGetter() + if case .endClassGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassGetter() } - set {operation = .endClassInstanceGetter(newValue)} + set {operation = .endClassGetter(newValue)} } - public var beginClassInstanceSetter: Fuzzilli_Protobuf_BeginClassInstanceSetter { + public var beginClassSetter: Fuzzilli_Protobuf_BeginClassSetter { get { - if case .beginClassInstanceSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceSetter() + if case .beginClassSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassSetter() } - set {operation = .beginClassInstanceSetter(newValue)} + set {operation = .beginClassSetter(newValue)} } - public var endClassInstanceSetter: Fuzzilli_Protobuf_EndClassInstanceSetter { + public var endClassSetter: Fuzzilli_Protobuf_EndClassSetter { get { - if case .endClassInstanceSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceSetter() + if case .endClassSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassSetter() } - set {operation = .endClassInstanceSetter(newValue)} - } - - public var classAddStaticProperty: Fuzzilli_Protobuf_ClassAddStaticProperty { - get { - if case .classAddStaticProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticProperty() - } - set {operation = .classAddStaticProperty(newValue)} - } - - public var classAddStaticElement: Fuzzilli_Protobuf_ClassAddStaticElement { - get { - if case .classAddStaticElement(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticElement() - } - set {operation = .classAddStaticElement(newValue)} - } - - public var classAddStaticComputedProperty: Fuzzilli_Protobuf_ClassAddStaticComputedProperty { - get { - if case .classAddStaticComputedProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticComputedProperty() - } - set {operation = .classAddStaticComputedProperty(newValue)} + set {operation = .endClassSetter(newValue)} } public var beginClassStaticInitializer: Fuzzilli_Protobuf_BeginClassStaticInitializer { @@ -441,116 +417,28 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassStaticInitializer(newValue)} } - public var beginClassStaticMethod: Fuzzilli_Protobuf_BeginClassStaticMethod { - get { - if case .beginClassStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticMethod() - } - set {operation = .beginClassStaticMethod(newValue)} - } - - public var endClassStaticMethod: Fuzzilli_Protobuf_EndClassStaticMethod { - get { - if case .endClassStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticMethod() - } - set {operation = .endClassStaticMethod(newValue)} - } - - public var beginClassStaticComputedMethod: Fuzzilli_Protobuf_BeginClassStaticComputedMethod { - get { - if case .beginClassStaticComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticComputedMethod() - } - set {operation = .beginClassStaticComputedMethod(newValue)} - } - - public var endClassStaticComputedMethod: Fuzzilli_Protobuf_EndClassStaticComputedMethod { - get { - if case .endClassStaticComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticComputedMethod() - } - set {operation = .endClassStaticComputedMethod(newValue)} - } - - public var beginClassStaticGetter: Fuzzilli_Protobuf_BeginClassStaticGetter { - get { - if case .beginClassStaticGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticGetter() - } - set {operation = .beginClassStaticGetter(newValue)} - } - - public var endClassStaticGetter: Fuzzilli_Protobuf_EndClassStaticGetter { + public var classAddPrivateProperty: Fuzzilli_Protobuf_ClassAddPrivateProperty { get { - if case .endClassStaticGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticGetter() + if case .classAddPrivateProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddPrivateProperty() } - set {operation = .endClassStaticGetter(newValue)} + set {operation = .classAddPrivateProperty(newValue)} } - public var beginClassStaticSetter: Fuzzilli_Protobuf_BeginClassStaticSetter { + public var beginClassPrivateMethod: Fuzzilli_Protobuf_BeginClassPrivateMethod { get { - if case .beginClassStaticSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticSetter() + if case .beginClassPrivateMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassPrivateMethod() } - set {operation = .beginClassStaticSetter(newValue)} + set {operation = .beginClassPrivateMethod(newValue)} } - public var endClassStaticSetter: Fuzzilli_Protobuf_EndClassStaticSetter { + public var endClassPrivateMethod: Fuzzilli_Protobuf_EndClassPrivateMethod { get { - if case .endClassStaticSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticSetter() + if case .endClassPrivateMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassPrivateMethod() } - set {operation = .endClassStaticSetter(newValue)} - } - - public var classAddPrivateInstanceProperty: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty { - get { - if case .classAddPrivateInstanceProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty() - } - set {operation = .classAddPrivateInstanceProperty(newValue)} - } - - public var beginClassPrivateInstanceMethod: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod { - get { - if case .beginClassPrivateInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod() - } - set {operation = .beginClassPrivateInstanceMethod(newValue)} - } - - public var endClassPrivateInstanceMethod: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod { - get { - if case .endClassPrivateInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - } - set {operation = .endClassPrivateInstanceMethod(newValue)} - } - - public var classAddPrivateStaticProperty: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty { - get { - if case .classAddPrivateStaticProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateStaticProperty() - } - set {operation = .classAddPrivateStaticProperty(newValue)} - } - - public var beginClassPrivateStaticMethod: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod { - get { - if case .beginClassPrivateStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateStaticMethod() - } - set {operation = .beginClassPrivateStaticMethod(newValue)} - } - - public var endClassPrivateStaticMethod: Fuzzilli_Protobuf_EndClassPrivateStaticMethod { - get { - if case .endClassPrivateStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateStaticMethod() - } - set {operation = .endClassPrivateStaticMethod(newValue)} + set {operation = .endClassPrivateMethod(newValue)} } public var endClassDefinition: Fuzzilli_Protobuf_EndClassDefinition { @@ -2805,36 +2693,22 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case beginClassDefinition(Fuzzilli_Protobuf_BeginClassDefinition) case beginClassConstructor(Fuzzilli_Protobuf_BeginClassConstructor) case endClassConstructor(Fuzzilli_Protobuf_EndClassConstructor) - case classAddInstanceProperty(Fuzzilli_Protobuf_ClassAddInstanceProperty) - case classAddInstanceElement(Fuzzilli_Protobuf_ClassAddInstanceElement) - case classAddInstanceComputedProperty(Fuzzilli_Protobuf_ClassAddInstanceComputedProperty) - case beginClassInstanceMethod(Fuzzilli_Protobuf_BeginClassInstanceMethod) - case endClassInstanceMethod(Fuzzilli_Protobuf_EndClassInstanceMethod) - case beginClassInstanceComputedMethod(Fuzzilli_Protobuf_BeginClassInstanceComputedMethod) - case endClassInstanceComputedMethod(Fuzzilli_Protobuf_EndClassInstanceComputedMethod) - case beginClassInstanceGetter(Fuzzilli_Protobuf_BeginClassInstanceGetter) - case endClassInstanceGetter(Fuzzilli_Protobuf_EndClassInstanceGetter) - case beginClassInstanceSetter(Fuzzilli_Protobuf_BeginClassInstanceSetter) - case endClassInstanceSetter(Fuzzilli_Protobuf_EndClassInstanceSetter) - case classAddStaticProperty(Fuzzilli_Protobuf_ClassAddStaticProperty) - case classAddStaticElement(Fuzzilli_Protobuf_ClassAddStaticElement) - case classAddStaticComputedProperty(Fuzzilli_Protobuf_ClassAddStaticComputedProperty) + case classAddProperty(Fuzzilli_Protobuf_ClassAddProperty) + case classAddElement(Fuzzilli_Protobuf_ClassAddElement) + case classAddComputedProperty(Fuzzilli_Protobuf_ClassAddComputedProperty) + case beginClassMethod(Fuzzilli_Protobuf_BeginClassMethod) + case endClassMethod(Fuzzilli_Protobuf_EndClassMethod) + case beginClassComputedMethod(Fuzzilli_Protobuf_BeginClassComputedMethod) + case endClassComputedMethod(Fuzzilli_Protobuf_EndClassComputedMethod) + case beginClassGetter(Fuzzilli_Protobuf_BeginClassGetter) + case endClassGetter(Fuzzilli_Protobuf_EndClassGetter) + case beginClassSetter(Fuzzilli_Protobuf_BeginClassSetter) + case endClassSetter(Fuzzilli_Protobuf_EndClassSetter) case beginClassStaticInitializer(Fuzzilli_Protobuf_BeginClassStaticInitializer) case endClassStaticInitializer(Fuzzilli_Protobuf_EndClassStaticInitializer) - case beginClassStaticMethod(Fuzzilli_Protobuf_BeginClassStaticMethod) - case endClassStaticMethod(Fuzzilli_Protobuf_EndClassStaticMethod) - case beginClassStaticComputedMethod(Fuzzilli_Protobuf_BeginClassStaticComputedMethod) - case endClassStaticComputedMethod(Fuzzilli_Protobuf_EndClassStaticComputedMethod) - case beginClassStaticGetter(Fuzzilli_Protobuf_BeginClassStaticGetter) - case endClassStaticGetter(Fuzzilli_Protobuf_EndClassStaticGetter) - case beginClassStaticSetter(Fuzzilli_Protobuf_BeginClassStaticSetter) - case endClassStaticSetter(Fuzzilli_Protobuf_EndClassStaticSetter) - case classAddPrivateInstanceProperty(Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty) - case beginClassPrivateInstanceMethod(Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod) - case endClassPrivateInstanceMethod(Fuzzilli_Protobuf_EndClassPrivateInstanceMethod) - case classAddPrivateStaticProperty(Fuzzilli_Protobuf_ClassAddPrivateStaticProperty) - case beginClassPrivateStaticMethod(Fuzzilli_Protobuf_BeginClassPrivateStaticMethod) - case endClassPrivateStaticMethod(Fuzzilli_Protobuf_EndClassPrivateStaticMethod) + case classAddPrivateProperty(Fuzzilli_Protobuf_ClassAddPrivateProperty) + case beginClassPrivateMethod(Fuzzilli_Protobuf_BeginClassPrivateMethod) + case endClassPrivateMethod(Fuzzilli_Protobuf_EndClassPrivateMethod) case endClassDefinition(Fuzzilli_Protobuf_EndClassDefinition) case createArray(Fuzzilli_Protobuf_CreateArray) case createIntArray(Fuzzilli_Protobuf_CreateIntArray) @@ -3160,7 +3034,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3594,891 +3468,709 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M } }() case 35: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceProperty? + var v: Fuzzilli_Protobuf_ClassAddProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceProperty(let m) = current {v = m} + if case .classAddProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceProperty(v) + self.operation = .classAddProperty(v) } }() case 36: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceElement? + var v: Fuzzilli_Protobuf_ClassAddElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceElement(let m) = current {v = m} + if case .classAddElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceElement(v) + self.operation = .classAddElement(v) } }() case 37: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty? + var v: Fuzzilli_Protobuf_ClassAddComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceComputedProperty(let m) = current {v = m} + if case .classAddComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceComputedProperty(v) + self.operation = .classAddComputedProperty(v) } }() case 38: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceMethod? + var v: Fuzzilli_Protobuf_BeginClassMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceMethod(let m) = current {v = m} + if case .beginClassMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceMethod(v) + self.operation = .beginClassMethod(v) } }() case 39: try { - var v: Fuzzilli_Protobuf_EndClassInstanceMethod? + var v: Fuzzilli_Protobuf_EndClassMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceMethod(let m) = current {v = m} + if case .endClassMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceMethod(v) + self.operation = .endClassMethod(v) } }() case 40: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod? + var v: Fuzzilli_Protobuf_BeginClassComputedMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceComputedMethod(let m) = current {v = m} + if case .beginClassComputedMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceComputedMethod(v) + self.operation = .beginClassComputedMethod(v) } }() case 41: try { - var v: Fuzzilli_Protobuf_EndClassInstanceComputedMethod? + var v: Fuzzilli_Protobuf_EndClassComputedMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceComputedMethod(let m) = current {v = m} + if case .endClassComputedMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceComputedMethod(v) + self.operation = .endClassComputedMethod(v) } }() case 42: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceGetter? + var v: Fuzzilli_Protobuf_BeginClassGetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceGetter(let m) = current {v = m} + if case .beginClassGetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceGetter(v) + self.operation = .beginClassGetter(v) } }() case 43: try { - var v: Fuzzilli_Protobuf_EndClassInstanceGetter? + var v: Fuzzilli_Protobuf_EndClassGetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceGetter(let m) = current {v = m} + if case .endClassGetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceGetter(v) + self.operation = .endClassGetter(v) } }() case 44: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceSetter? + var v: Fuzzilli_Protobuf_BeginClassSetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceSetter(let m) = current {v = m} + if case .beginClassSetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceSetter(v) + self.operation = .beginClassSetter(v) } }() case 45: try { - var v: Fuzzilli_Protobuf_EndClassInstanceSetter? + var v: Fuzzilli_Protobuf_EndClassSetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceSetter(let m) = current {v = m} + if case .endClassSetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceSetter(v) + self.operation = .endClassSetter(v) } }() case 46: try { - var v: Fuzzilli_Protobuf_ClassAddStaticProperty? + var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticProperty(let m) = current {v = m} + if case .beginClassStaticInitializer(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticProperty(v) + self.operation = .beginClassStaticInitializer(v) } }() case 47: try { - var v: Fuzzilli_Protobuf_ClassAddStaticElement? + var v: Fuzzilli_Protobuf_EndClassStaticInitializer? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticElement(let m) = current {v = m} + if case .endClassStaticInitializer(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticElement(v) + self.operation = .endClassStaticInitializer(v) } }() case 48: try { - var v: Fuzzilli_Protobuf_ClassAddStaticComputedProperty? + var v: Fuzzilli_Protobuf_ClassAddPrivateProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticComputedProperty(let m) = current {v = m} + if case .classAddPrivateProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticComputedProperty(v) + self.operation = .classAddPrivateProperty(v) } }() case 49: try { - var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? + var v: Fuzzilli_Protobuf_BeginClassPrivateMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticInitializer(let m) = current {v = m} + if case .beginClassPrivateMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticInitializer(v) + self.operation = .beginClassPrivateMethod(v) } }() case 50: try { - var v: Fuzzilli_Protobuf_EndClassStaticInitializer? + var v: Fuzzilli_Protobuf_EndClassPrivateMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticInitializer(let m) = current {v = m} + if case .endClassPrivateMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticInitializer(v) + self.operation = .endClassPrivateMethod(v) } }() case 51: try { - var v: Fuzzilli_Protobuf_BeginClassStaticMethod? + var v: Fuzzilli_Protobuf_EndClassDefinition? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticMethod(let m) = current {v = m} + if case .endClassDefinition(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticMethod(v) + self.operation = .endClassDefinition(v) } }() case 52: try { - var v: Fuzzilli_Protobuf_EndClassStaticMethod? + var v: Fuzzilli_Protobuf_CreateArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticMethod(let m) = current {v = m} + if case .createArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticMethod(v) + self.operation = .createArray(v) } }() case 53: try { - var v: Fuzzilli_Protobuf_BeginClassStaticComputedMethod? + var v: Fuzzilli_Protobuf_CreateIntArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticComputedMethod(let m) = current {v = m} + if case .createIntArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticComputedMethod(v) + self.operation = .createIntArray(v) } }() case 54: try { - var v: Fuzzilli_Protobuf_EndClassStaticComputedMethod? + var v: Fuzzilli_Protobuf_CreateFloatArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticComputedMethod(let m) = current {v = m} + if case .createFloatArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticComputedMethod(v) + self.operation = .createFloatArray(v) } }() case 55: try { - var v: Fuzzilli_Protobuf_BeginClassStaticGetter? + var v: Fuzzilli_Protobuf_CreateArrayWithSpread? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticGetter(let m) = current {v = m} + if case .createArrayWithSpread(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticGetter(v) + self.operation = .createArrayWithSpread(v) } }() case 56: try { - var v: Fuzzilli_Protobuf_EndClassStaticGetter? + var v: Fuzzilli_Protobuf_CreateTemplateString? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticGetter(let m) = current {v = m} + if case .createTemplateString(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticGetter(v) + self.operation = .createTemplateString(v) } }() case 57: try { - var v: Fuzzilli_Protobuf_BeginClassStaticSetter? + var v: Fuzzilli_Protobuf_GetProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticSetter(let m) = current {v = m} + if case .getProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticSetter(v) + self.operation = .getProperty(v) } }() case 58: try { - var v: Fuzzilli_Protobuf_EndClassStaticSetter? + var v: Fuzzilli_Protobuf_SetProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticSetter(let m) = current {v = m} + if case .setProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticSetter(v) + self.operation = .setProperty(v) } }() case 59: try { - var v: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty? + var v: Fuzzilli_Protobuf_UpdateProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddPrivateInstanceProperty(let m) = current {v = m} + if case .updateProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddPrivateInstanceProperty(v) + self.operation = .updateProperty(v) } }() case 60: try { - var v: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod? + var v: Fuzzilli_Protobuf_DeleteProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassPrivateInstanceMethod(let m) = current {v = m} + if case .deleteProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassPrivateInstanceMethod(v) + self.operation = .deleteProperty(v) } }() case 61: try { - var v: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod? + var v: Fuzzilli_Protobuf_ConfigureProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassPrivateInstanceMethod(let m) = current {v = m} + if case .configureProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassPrivateInstanceMethod(v) + self.operation = .configureProperty(v) } }() case 62: try { - var v: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty? + var v: Fuzzilli_Protobuf_GetElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddPrivateStaticProperty(let m) = current {v = m} + if case .getElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddPrivateStaticProperty(v) + self.operation = .getElement(v) } }() case 63: try { - var v: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod? + var v: Fuzzilli_Protobuf_SetElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassPrivateStaticMethod(let m) = current {v = m} + if case .setElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassPrivateStaticMethod(v) + self.operation = .setElement(v) } }() case 64: try { - var v: Fuzzilli_Protobuf_EndClassPrivateStaticMethod? + var v: Fuzzilli_Protobuf_UpdateElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassPrivateStaticMethod(let m) = current {v = m} + if case .updateElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassPrivateStaticMethod(v) + self.operation = .updateElement(v) } }() case 65: try { - var v: Fuzzilli_Protobuf_EndClassDefinition? + var v: Fuzzilli_Protobuf_DeleteElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassDefinition(let m) = current {v = m} + if case .deleteElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassDefinition(v) + self.operation = .deleteElement(v) } }() case 66: try { - var v: Fuzzilli_Protobuf_CreateArray? + var v: Fuzzilli_Protobuf_ConfigureElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createArray(let m) = current {v = m} + if case .configureElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createArray(v) + self.operation = .configureElement(v) } }() case 67: try { - var v: Fuzzilli_Protobuf_CreateIntArray? + var v: Fuzzilli_Protobuf_GetComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createIntArray(let m) = current {v = m} + if case .getComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createIntArray(v) + self.operation = .getComputedProperty(v) } }() case 68: try { - var v: Fuzzilli_Protobuf_CreateFloatArray? + var v: Fuzzilli_Protobuf_SetComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createFloatArray(let m) = current {v = m} + if case .setComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createFloatArray(v) + self.operation = .setComputedProperty(v) } }() case 69: try { - var v: Fuzzilli_Protobuf_CreateArrayWithSpread? + var v: Fuzzilli_Protobuf_UpdateComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createArrayWithSpread(let m) = current {v = m} + if case .updateComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createArrayWithSpread(v) + self.operation = .updateComputedProperty(v) } }() case 70: try { - var v: Fuzzilli_Protobuf_CreateTemplateString? + var v: Fuzzilli_Protobuf_DeleteComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createTemplateString(let m) = current {v = m} + if case .deleteComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createTemplateString(v) + self.operation = .deleteComputedProperty(v) } }() case 71: try { - var v: Fuzzilli_Protobuf_GetProperty? + var v: Fuzzilli_Protobuf_ConfigureComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getProperty(let m) = current {v = m} + if case .configureComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getProperty(v) + self.operation = .configureComputedProperty(v) } }() case 72: try { - var v: Fuzzilli_Protobuf_SetProperty? + var v: Fuzzilli_Protobuf_TypeOf? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setProperty(let m) = current {v = m} + if case .typeOf(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setProperty(v) + self.operation = .typeOf(v) } }() case 73: try { - var v: Fuzzilli_Protobuf_UpdateProperty? + var v: Fuzzilli_Protobuf_Void? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateProperty(let m) = current {v = m} + if case .void(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateProperty(v) + self.operation = .void(v) } }() case 74: try { - var v: Fuzzilli_Protobuf_DeleteProperty? + var v: Fuzzilli_Protobuf_TestInstanceOf? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteProperty(let m) = current {v = m} + if case .testInstanceOf(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteProperty(v) + self.operation = .testInstanceOf(v) } }() case 75: try { - var v: Fuzzilli_Protobuf_ConfigureProperty? + var v: Fuzzilli_Protobuf_TestIn? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureProperty(let m) = current {v = m} + if case .testIn(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureProperty(v) + self.operation = .testIn(v) } }() case 76: try { - var v: Fuzzilli_Protobuf_GetElement? + var v: Fuzzilli_Protobuf_BeginPlainFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getElement(let m) = current {v = m} + if case .beginPlainFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getElement(v) + self.operation = .beginPlainFunction(v) } }() case 77: try { - var v: Fuzzilli_Protobuf_SetElement? + var v: Fuzzilli_Protobuf_EndPlainFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setElement(let m) = current {v = m} + if case .endPlainFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setElement(v) + self.operation = .endPlainFunction(v) } }() case 78: try { - var v: Fuzzilli_Protobuf_UpdateElement? + var v: Fuzzilli_Protobuf_BeginArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateElement(let m) = current {v = m} + if case .beginArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateElement(v) + self.operation = .beginArrowFunction(v) } }() case 79: try { - var v: Fuzzilli_Protobuf_DeleteElement? + var v: Fuzzilli_Protobuf_EndArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteElement(let m) = current {v = m} + if case .endArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteElement(v) + self.operation = .endArrowFunction(v) } }() case 80: try { - var v: Fuzzilli_Protobuf_ConfigureElement? + var v: Fuzzilli_Protobuf_BeginGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureElement(let m) = current {v = m} + if case .beginGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureElement(v) + self.operation = .beginGeneratorFunction(v) } }() case 81: try { - var v: Fuzzilli_Protobuf_GetComputedProperty? + var v: Fuzzilli_Protobuf_EndGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getComputedProperty(let m) = current {v = m} + if case .endGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getComputedProperty(v) + self.operation = .endGeneratorFunction(v) } }() case 82: try { - var v: Fuzzilli_Protobuf_SetComputedProperty? + var v: Fuzzilli_Protobuf_BeginAsyncFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setComputedProperty(let m) = current {v = m} + if case .beginAsyncFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setComputedProperty(v) + self.operation = .beginAsyncFunction(v) } }() case 83: try { - var v: Fuzzilli_Protobuf_UpdateComputedProperty? + var v: Fuzzilli_Protobuf_EndAsyncFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateComputedProperty(let m) = current {v = m} + if case .endAsyncFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateComputedProperty(v) + self.operation = .endAsyncFunction(v) } }() case 84: try { - var v: Fuzzilli_Protobuf_DeleteComputedProperty? + var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteComputedProperty(let m) = current {v = m} + if case .beginAsyncArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteComputedProperty(v) + self.operation = .beginAsyncArrowFunction(v) } }() case 85: try { - var v: Fuzzilli_Protobuf_ConfigureComputedProperty? + var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureComputedProperty(let m) = current {v = m} + if case .endAsyncArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureComputedProperty(v) + self.operation = .endAsyncArrowFunction(v) } }() case 86: try { - var v: Fuzzilli_Protobuf_TypeOf? + var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .typeOf(let m) = current {v = m} + if case .beginAsyncGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .typeOf(v) + self.operation = .beginAsyncGeneratorFunction(v) } }() case 87: try { - var v: Fuzzilli_Protobuf_Void? + var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .void(let m) = current {v = m} + if case .endAsyncGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .void(v) + self.operation = .endAsyncGeneratorFunction(v) } }() case 88: try { - var v: Fuzzilli_Protobuf_TestInstanceOf? + var v: Fuzzilli_Protobuf_BeginConstructor? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .testInstanceOf(let m) = current {v = m} + if case .beginConstructor(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .testInstanceOf(v) + self.operation = .beginConstructor(v) } }() case 89: try { - var v: Fuzzilli_Protobuf_TestIn? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .testIn(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .testIn(v) - } - }() - case 90: try { - var v: Fuzzilli_Protobuf_BeginPlainFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginPlainFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginPlainFunction(v) - } - }() - case 91: try { - var v: Fuzzilli_Protobuf_EndPlainFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endPlainFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endPlainFunction(v) - } - }() - case 92: try { - var v: Fuzzilli_Protobuf_BeginArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginArrowFunction(v) - } - }() - case 93: try { - var v: Fuzzilli_Protobuf_EndArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endArrowFunction(v) - } - }() - case 94: try { - var v: Fuzzilli_Protobuf_BeginGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginGeneratorFunction(v) - } - }() - case 95: try { - var v: Fuzzilli_Protobuf_EndGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endGeneratorFunction(v) - } - }() - case 96: try { - var v: Fuzzilli_Protobuf_BeginAsyncFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncFunction(v) - } - }() - case 97: try { - var v: Fuzzilli_Protobuf_EndAsyncFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncFunction(v) - } - }() - case 98: try { - var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncArrowFunction(v) - } - }() - case 99: try { - var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncArrowFunction(v) - } - }() - case 100: try { - var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncGeneratorFunction(v) - } - }() - case 101: try { - var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncGeneratorFunction(v) - } - }() - case 102: try { - var v: Fuzzilli_Protobuf_BeginConstructor? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginConstructor(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginConstructor(v) - } - }() - case 103: try { - var v: Fuzzilli_Protobuf_EndConstructor? + var v: Fuzzilli_Protobuf_EndConstructor? var hadOneofValue = false if let current = self.operation { hadOneofValue = true @@ -4490,7 +4182,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endConstructor(v) } }() - case 104: try { + case 90: try { var v: Fuzzilli_Protobuf_Directive? var hadOneofValue = false if let current = self.operation { @@ -4503,7 +4195,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .directive(v) } }() - case 105: try { + case 91: try { var v: Fuzzilli_Protobuf_Return? var hadOneofValue = false if let current = self.operation { @@ -4516,7 +4208,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .return(v) } }() - case 106: try { + case 92: try { var v: Fuzzilli_Protobuf_Yield? var hadOneofValue = false if let current = self.operation { @@ -4529,7 +4221,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .yield(v) } }() - case 107: try { + case 93: try { var v: Fuzzilli_Protobuf_YieldEach? var hadOneofValue = false if let current = self.operation { @@ -4542,7 +4234,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .yieldEach(v) } }() - case 108: try { + case 94: try { var v: Fuzzilli_Protobuf_Await? var hadOneofValue = false if let current = self.operation { @@ -4555,7 +4247,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .await(v) } }() - case 109: try { + case 95: try { var v: Fuzzilli_Protobuf_CallFunction? var hadOneofValue = false if let current = self.operation { @@ -4568,7 +4260,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callFunction(v) } }() - case 110: try { + case 96: try { var v: Fuzzilli_Protobuf_CallFunctionWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4581,7 +4273,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callFunctionWithSpread(v) } }() - case 111: try { + case 97: try { var v: Fuzzilli_Protobuf_Construct? var hadOneofValue = false if let current = self.operation { @@ -4594,7 +4286,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .construct(v) } }() - case 112: try { + case 98: try { var v: Fuzzilli_Protobuf_ConstructWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4607,7 +4299,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constructWithSpread(v) } }() - case 113: try { + case 99: try { var v: Fuzzilli_Protobuf_CallMethod? var hadOneofValue = false if let current = self.operation { @@ -4620,7 +4312,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callMethod(v) } }() - case 114: try { + case 100: try { var v: Fuzzilli_Protobuf_CallMethodWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4633,7 +4325,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callMethodWithSpread(v) } }() - case 115: try { + case 101: try { var v: Fuzzilli_Protobuf_CallComputedMethod? var hadOneofValue = false if let current = self.operation { @@ -4646,7 +4338,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callComputedMethod(v) } }() - case 116: try { + case 102: try { var v: Fuzzilli_Protobuf_CallComputedMethodWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4659,7 +4351,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callComputedMethodWithSpread(v) } }() - case 117: try { + case 103: try { var v: Fuzzilli_Protobuf_UnaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4672,7 +4364,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .unaryOperation(v) } }() - case 118: try { + case 104: try { var v: Fuzzilli_Protobuf_BinaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4685,7 +4377,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .binaryOperation(v) } }() - case 119: try { + case 105: try { var v: Fuzzilli_Protobuf_TernaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4698,7 +4390,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .ternaryOperation(v) } }() - case 120: try { + case 106: try { var v: Fuzzilli_Protobuf_Update? var hadOneofValue = false if let current = self.operation { @@ -4711,7 +4403,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .update(v) } }() - case 121: try { + case 107: try { var v: Fuzzilli_Protobuf_Dup? var hadOneofValue = false if let current = self.operation { @@ -4724,7 +4416,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .dup(v) } }() - case 122: try { + case 108: try { var v: Fuzzilli_Protobuf_Reassign? var hadOneofValue = false if let current = self.operation { @@ -4737,7 +4429,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .reassign(v) } }() - case 123: try { + case 109: try { var v: Fuzzilli_Protobuf_DestructArray? var hadOneofValue = false if let current = self.operation { @@ -4750,7 +4442,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructArray(v) } }() - case 124: try { + case 110: try { var v: Fuzzilli_Protobuf_DestructArrayAndReassign? var hadOneofValue = false if let current = self.operation { @@ -4763,7 +4455,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructArrayAndReassign(v) } }() - case 125: try { + case 111: try { var v: Fuzzilli_Protobuf_DestructObject? var hadOneofValue = false if let current = self.operation { @@ -4776,7 +4468,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructObject(v) } }() - case 126: try { + case 112: try { var v: Fuzzilli_Protobuf_DestructObjectAndReassign? var hadOneofValue = false if let current = self.operation { @@ -4789,7 +4481,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructObjectAndReassign(v) } }() - case 127: try { + case 113: try { var v: Fuzzilli_Protobuf_Compare? var hadOneofValue = false if let current = self.operation { @@ -4802,7 +4494,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .compare(v) } }() - case 128: try { + case 114: try { var v: Fuzzilli_Protobuf_Eval? var hadOneofValue = false if let current = self.operation { @@ -4815,7 +4507,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .eval(v) } }() - case 129: try { + case 115: try { var v: Fuzzilli_Protobuf_BeginWith? var hadOneofValue = false if let current = self.operation { @@ -4828,7 +4520,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWith(v) } }() - case 130: try { + case 116: try { var v: Fuzzilli_Protobuf_EndWith? var hadOneofValue = false if let current = self.operation { @@ -4841,7 +4533,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWith(v) } }() - case 131: try { + case 117: try { var v: Fuzzilli_Protobuf_CallSuperConstructor? var hadOneofValue = false if let current = self.operation { @@ -4854,7 +4546,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callSuperConstructor(v) } }() - case 132: try { + case 118: try { var v: Fuzzilli_Protobuf_CallSuperMethod? var hadOneofValue = false if let current = self.operation { @@ -4867,7 +4559,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callSuperMethod(v) } }() - case 133: try { + case 119: try { var v: Fuzzilli_Protobuf_GetPrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4880,7 +4572,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getPrivateProperty(v) } }() - case 134: try { + case 120: try { var v: Fuzzilli_Protobuf_SetPrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4893,7 +4585,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setPrivateProperty(v) } }() - case 135: try { + case 121: try { var v: Fuzzilli_Protobuf_UpdatePrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4906,7 +4598,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .updatePrivateProperty(v) } }() - case 136: try { + case 122: try { var v: Fuzzilli_Protobuf_CallPrivateMethod? var hadOneofValue = false if let current = self.operation { @@ -4919,7 +4611,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callPrivateMethod(v) } }() - case 137: try { + case 123: try { var v: Fuzzilli_Protobuf_GetSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4932,7 +4624,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getSuperProperty(v) } }() - case 138: try { + case 124: try { var v: Fuzzilli_Protobuf_SetSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4945,7 +4637,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setSuperProperty(v) } }() - case 139: try { + case 125: try { var v: Fuzzilli_Protobuf_GetComputedSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4958,7 +4650,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getComputedSuperProperty(v) } }() - case 140: try { + case 126: try { var v: Fuzzilli_Protobuf_SetComputedSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4971,7 +4663,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setComputedSuperProperty(v) } }() - case 141: try { + case 127: try { var v: Fuzzilli_Protobuf_UpdateSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4984,7 +4676,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .updateSuperProperty(v) } }() - case 142: try { + case 128: try { var v: Fuzzilli_Protobuf_BeginIf? var hadOneofValue = false if let current = self.operation { @@ -4997,7 +4689,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginIf(v) } }() - case 143: try { + case 129: try { var v: Fuzzilli_Protobuf_BeginElse? var hadOneofValue = false if let current = self.operation { @@ -5010,7 +4702,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginElse(v) } }() - case 144: try { + case 130: try { var v: Fuzzilli_Protobuf_EndIf? var hadOneofValue = false if let current = self.operation { @@ -5023,7 +4715,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endIf(v) } }() - case 145: try { + case 131: try { var v: Fuzzilli_Protobuf_BeginWhileLoopHeader? var hadOneofValue = false if let current = self.operation { @@ -5036,7 +4728,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWhileLoopHeader(v) } }() - case 146: try { + case 132: try { var v: Fuzzilli_Protobuf_BeginWhileLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5049,7 +4741,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWhileLoopBody(v) } }() - case 147: try { + case 133: try { var v: Fuzzilli_Protobuf_EndWhileLoop? var hadOneofValue = false if let current = self.operation { @@ -5062,7 +4754,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWhileLoop(v) } }() - case 148: try { + case 134: try { var v: Fuzzilli_Protobuf_BeginDoWhileLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5075,7 +4767,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginDoWhileLoopBody(v) } }() - case 149: try { + case 135: try { var v: Fuzzilli_Protobuf_BeginDoWhileLoopHeader? var hadOneofValue = false if let current = self.operation { @@ -5088,7 +4780,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginDoWhileLoopHeader(v) } }() - case 150: try { + case 136: try { var v: Fuzzilli_Protobuf_EndDoWhileLoop? var hadOneofValue = false if let current = self.operation { @@ -5101,7 +4793,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endDoWhileLoop(v) } }() - case 151: try { + case 137: try { var v: Fuzzilli_Protobuf_BeginForLoopInitializer? var hadOneofValue = false if let current = self.operation { @@ -5114,7 +4806,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopInitializer(v) } }() - case 152: try { + case 138: try { var v: Fuzzilli_Protobuf_BeginForLoopCondition? var hadOneofValue = false if let current = self.operation { @@ -5127,7 +4819,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopCondition(v) } }() - case 153: try { + case 139: try { var v: Fuzzilli_Protobuf_BeginForLoopAfterthought? var hadOneofValue = false if let current = self.operation { @@ -5140,7 +4832,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopAfterthought(v) } }() - case 154: try { + case 140: try { var v: Fuzzilli_Protobuf_BeginForLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5153,7 +4845,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopBody(v) } }() - case 155: try { + case 141: try { var v: Fuzzilli_Protobuf_EndForLoop? var hadOneofValue = false if let current = self.operation { @@ -5166,7 +4858,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForLoop(v) } }() - case 156: try { + case 142: try { var v: Fuzzilli_Protobuf_BeginForInLoop? var hadOneofValue = false if let current = self.operation { @@ -5179,7 +4871,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForInLoop(v) } }() - case 157: try { + case 143: try { var v: Fuzzilli_Protobuf_EndForInLoop? var hadOneofValue = false if let current = self.operation { @@ -5192,7 +4884,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForInLoop(v) } }() - case 158: try { + case 144: try { var v: Fuzzilli_Protobuf_BeginForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -5205,7 +4897,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoop(v) } }() - case 159: try { + case 145: try { var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? var hadOneofValue = false if let current = self.operation { @@ -5218,7 +4910,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoopWithDestruct(v) } }() - case 160: try { + case 146: try { var v: Fuzzilli_Protobuf_EndForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -5231,7 +4923,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForOfLoop(v) } }() - case 161: try { + case 147: try { var v: Fuzzilli_Protobuf_BeginRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -5244,7 +4936,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginRepeatLoop(v) } }() - case 162: try { + case 148: try { var v: Fuzzilli_Protobuf_EndRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -5257,7 +4949,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endRepeatLoop(v) } }() - case 163: try { + case 149: try { var v: Fuzzilli_Protobuf_LoopBreak? var hadOneofValue = false if let current = self.operation { @@ -5270,7 +4962,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopBreak(v) } }() - case 164: try { + case 150: try { var v: Fuzzilli_Protobuf_LoopContinue? var hadOneofValue = false if let current = self.operation { @@ -5283,7 +4975,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopContinue(v) } }() - case 165: try { + case 151: try { var v: Fuzzilli_Protobuf_BeginTry? var hadOneofValue = false if let current = self.operation { @@ -5296,7 +4988,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginTry(v) } }() - case 166: try { + case 152: try { var v: Fuzzilli_Protobuf_BeginCatch? var hadOneofValue = false if let current = self.operation { @@ -5309,7 +5001,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCatch(v) } }() - case 167: try { + case 153: try { var v: Fuzzilli_Protobuf_BeginFinally? var hadOneofValue = false if let current = self.operation { @@ -5322,7 +5014,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginFinally(v) } }() - case 168: try { + case 154: try { var v: Fuzzilli_Protobuf_EndTryCatchFinally? var hadOneofValue = false if let current = self.operation { @@ -5335,7 +5027,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endTryCatchFinally(v) } }() - case 169: try { + case 155: try { var v: Fuzzilli_Protobuf_ThrowException? var hadOneofValue = false if let current = self.operation { @@ -5348,7 +5040,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .throwException(v) } }() - case 170: try { + case 156: try { var v: Fuzzilli_Protobuf_BeginCodeString? var hadOneofValue = false if let current = self.operation { @@ -5361,7 +5053,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCodeString(v) } }() - case 171: try { + case 157: try { var v: Fuzzilli_Protobuf_EndCodeString? var hadOneofValue = false if let current = self.operation { @@ -5374,7 +5066,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endCodeString(v) } }() - case 172: try { + case 158: try { var v: Fuzzilli_Protobuf_BeginBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -5387,7 +5079,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginBlockStatement(v) } }() - case 173: try { + case 159: try { var v: Fuzzilli_Protobuf_EndBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -5400,7 +5092,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endBlockStatement(v) } }() - case 174: try { + case 160: try { var v: Fuzzilli_Protobuf_BeginSwitch? var hadOneofValue = false if let current = self.operation { @@ -5413,7 +5105,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitch(v) } }() - case 175: try { + case 161: try { var v: Fuzzilli_Protobuf_BeginSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -5426,7 +5118,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchCase(v) } }() - case 176: try { + case 162: try { var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? var hadOneofValue = false if let current = self.operation { @@ -5439,7 +5131,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchDefaultCase(v) } }() - case 177: try { + case 163: try { var v: Fuzzilli_Protobuf_EndSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -5452,7 +5144,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitchCase(v) } }() - case 178: try { + case 164: try { var v: Fuzzilli_Protobuf_EndSwitch? var hadOneofValue = false if let current = self.operation { @@ -5465,7 +5157,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitch(v) } }() - case 179: try { + case 165: try { var v: Fuzzilli_Protobuf_SwitchBreak? var hadOneofValue = false if let current = self.operation { @@ -5478,7 +5170,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .switchBreak(v) } }() - case 180: try { + case 166: try { var v: Fuzzilli_Protobuf_LoadNewTarget? var hadOneofValue = false if let current = self.operation { @@ -5491,7 +5183,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loadNewTarget(v) } }() - case 181: try { + case 167: try { var v: Fuzzilli_Protobuf_Print? var hadOneofValue = false if let current = self.operation { @@ -5504,7 +5196,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .print(v) } }() - case 182: try { + case 168: try { var v: Fuzzilli_Protobuf_Explore? var hadOneofValue = false if let current = self.operation { @@ -5517,7 +5209,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .explore(v) } }() - case 183: try { + case 169: try { var v: Fuzzilli_Protobuf_Probe? var hadOneofValue = false if let current = self.operation { @@ -5530,7 +5222,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .probe(v) } }() - case 184: try { + case 170: try { var v: Fuzzilli_Protobuf_Fixup? var hadOneofValue = false if let current = self.operation { @@ -5543,7 +5235,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .fixup(v) } }() - case 185: try { + case 171: try { var v: Fuzzilli_Protobuf_BeginWasmModule? var hadOneofValue = false if let current = self.operation { @@ -5556,7 +5248,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWasmModule(v) } }() - case 186: try { + case 172: try { var v: Fuzzilli_Protobuf_EndWasmModule? var hadOneofValue = false if let current = self.operation { @@ -5569,7 +5261,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWasmModule(v) } }() - case 187: try { + case 173: try { var v: Fuzzilli_Protobuf_CreateWasmGlobal? var hadOneofValue = false if let current = self.operation { @@ -5582,7 +5274,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmGlobal(v) } }() - case 188: try { + case 174: try { var v: Fuzzilli_Protobuf_CreateWasmMemory? var hadOneofValue = false if let current = self.operation { @@ -5595,7 +5287,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmMemory(v) } }() - case 189: try { + case 175: try { var v: Fuzzilli_Protobuf_CreateWasmTable? var hadOneofValue = false if let current = self.operation { @@ -5608,7 +5300,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmTable(v) } }() - case 190: try { + case 176: try { var v: Fuzzilli_Protobuf_CreateWasmJSTag? var hadOneofValue = false if let current = self.operation { @@ -5621,7 +5313,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmJstag(v) } }() - case 191: try { + case 177: try { var v: Fuzzilli_Protobuf_CreateWasmTag? var hadOneofValue = false if let current = self.operation { @@ -5634,7 +5326,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmTag(v) } }() - case 192: try { + case 178: try { var v: Fuzzilli_Protobuf_WrapPromising? var hadOneofValue = false if let current = self.operation { @@ -5647,7 +5339,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wrapPromising(v) } }() - case 193: try { + case 179: try { var v: Fuzzilli_Protobuf_WrapSuspending? var hadOneofValue = false if let current = self.operation { @@ -5660,7 +5352,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wrapSuspending(v) } }() - case 194: try { + case 180: try { var v: Fuzzilli_Protobuf_BindMethod? var hadOneofValue = false if let current = self.operation { @@ -5673,7 +5365,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .bindMethod(v) } }() - case 195: try { + case 181: try { var v: Fuzzilli_Protobuf_BindFunction? var hadOneofValue = false if let current = self.operation { @@ -5686,7 +5378,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .bindFunction(v) } }() - case 196: try { + case 182: try { var v: Fuzzilli_Protobuf_Consti64? var hadOneofValue = false if let current = self.operation { @@ -5699,7 +5391,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .consti64(v) } }() - case 197: try { + case 183: try { var v: Fuzzilli_Protobuf_Consti32? var hadOneofValue = false if let current = self.operation { @@ -5712,7 +5404,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .consti32(v) } }() - case 198: try { + case 184: try { var v: Fuzzilli_Protobuf_Constf32? var hadOneofValue = false if let current = self.operation { @@ -5725,7 +5417,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constf32(v) } }() - case 199: try { + case 185: try { var v: Fuzzilli_Protobuf_Constf64? var hadOneofValue = false if let current = self.operation { @@ -5738,7 +5430,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constf64(v) } }() - case 200: try { + case 186: try { var v: Fuzzilli_Protobuf_WasmReturn? var hadOneofValue = false if let current = self.operation { @@ -5751,7 +5443,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturn(v) } }() - case 201: try { + case 187: try { var v: Fuzzilli_Protobuf_WasmJsCall? var hadOneofValue = false if let current = self.operation { @@ -5764,7 +5456,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmJsCall(v) } }() - case 202: try { + case 188: try { var v: Fuzzilli_Protobuf_Wasmi32CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5777,7 +5469,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32CompareOp(v) } }() - case 203: try { + case 189: try { var v: Fuzzilli_Protobuf_Wasmi64CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5790,7 +5482,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64CompareOp(v) } }() - case 204: try { + case 190: try { var v: Fuzzilli_Protobuf_Wasmf32CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5803,7 +5495,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32CompareOp(v) } }() - case 205: try { + case 191: try { var v: Fuzzilli_Protobuf_Wasmf64CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5816,7 +5508,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64CompareOp(v) } }() - case 206: try { + case 192: try { var v: Fuzzilli_Protobuf_Wasmi32EqualZero? var hadOneofValue = false if let current = self.operation { @@ -5829,7 +5521,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32EqualZero(v) } }() - case 207: try { + case 193: try { var v: Fuzzilli_Protobuf_Wasmi64EqualZero? var hadOneofValue = false if let current = self.operation { @@ -5842,7 +5534,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64EqualZero(v) } }() - case 208: try { + case 194: try { var v: Fuzzilli_Protobuf_Wasmi32BinOp? var hadOneofValue = false if let current = self.operation { @@ -5855,7 +5547,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32BinOp(v) } }() - case 209: try { + case 195: try { var v: Fuzzilli_Protobuf_Wasmi64BinOp? var hadOneofValue = false if let current = self.operation { @@ -5868,7 +5560,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64BinOp(v) } }() - case 210: try { + case 196: try { var v: Fuzzilli_Protobuf_Wasmi32UnOp? var hadOneofValue = false if let current = self.operation { @@ -5881,7 +5573,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32UnOp(v) } }() - case 211: try { + case 197: try { var v: Fuzzilli_Protobuf_Wasmi64UnOp? var hadOneofValue = false if let current = self.operation { @@ -5894,7 +5586,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64UnOp(v) } }() - case 212: try { + case 198: try { var v: Fuzzilli_Protobuf_Wasmf32BinOp? var hadOneofValue = false if let current = self.operation { @@ -5907,7 +5599,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32BinOp(v) } }() - case 213: try { + case 199: try { var v: Fuzzilli_Protobuf_Wasmf64BinOp? var hadOneofValue = false if let current = self.operation { @@ -5920,7 +5612,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64BinOp(v) } }() - case 214: try { + case 200: try { var v: Fuzzilli_Protobuf_Wasmf32UnOp? var hadOneofValue = false if let current = self.operation { @@ -5933,7 +5625,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32UnOp(v) } }() - case 215: try { + case 201: try { var v: Fuzzilli_Protobuf_Wasmf64UnOp? var hadOneofValue = false if let current = self.operation { @@ -5946,7 +5638,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64UnOp(v) } }() - case 216: try { + case 202: try { var v: Fuzzilli_Protobuf_WasmWrapi64Toi32? var hadOneofValue = false if let current = self.operation { @@ -5959,7 +5651,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmWrapi64Toi32(v) } }() - case 217: try { + case 203: try { var v: Fuzzilli_Protobuf_WasmTruncatef32Toi32? var hadOneofValue = false if let current = self.operation { @@ -5972,7 +5664,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef32Toi32(v) } }() - case 218: try { + case 204: try { var v: Fuzzilli_Protobuf_WasmTruncatef64Toi32? var hadOneofValue = false if let current = self.operation { @@ -5985,7 +5677,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef64Toi32(v) } }() - case 219: try { + case 205: try { var v: Fuzzilli_Protobuf_WasmExtendi32Toi64? var hadOneofValue = false if let current = self.operation { @@ -5998,7 +5690,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmExtendi32Toi64(v) } }() - case 220: try { + case 206: try { var v: Fuzzilli_Protobuf_WasmTruncatef32Toi64? var hadOneofValue = false if let current = self.operation { @@ -6011,7 +5703,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef32Toi64(v) } }() - case 221: try { + case 207: try { var v: Fuzzilli_Protobuf_WasmTruncatef64Toi64? var hadOneofValue = false if let current = self.operation { @@ -6024,7 +5716,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef64Toi64(v) } }() - case 222: try { + case 208: try { var v: Fuzzilli_Protobuf_WasmConverti32Tof32? var hadOneofValue = false if let current = self.operation { @@ -6037,7 +5729,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti32Tof32(v) } }() - case 223: try { + case 209: try { var v: Fuzzilli_Protobuf_WasmConverti64Tof32? var hadOneofValue = false if let current = self.operation { @@ -6050,7 +5742,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti64Tof32(v) } }() - case 224: try { + case 210: try { var v: Fuzzilli_Protobuf_WasmDemotef64Tof32? var hadOneofValue = false if let current = self.operation { @@ -6063,7 +5755,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDemotef64Tof32(v) } }() - case 225: try { + case 211: try { var v: Fuzzilli_Protobuf_WasmConverti32Tof64? var hadOneofValue = false if let current = self.operation { @@ -6076,7 +5768,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti32Tof64(v) } }() - case 226: try { + case 212: try { var v: Fuzzilli_Protobuf_WasmConverti64Tof64? var hadOneofValue = false if let current = self.operation { @@ -6089,7 +5781,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti64Tof64(v) } }() - case 227: try { + case 213: try { var v: Fuzzilli_Protobuf_WasmPromotef32Tof64? var hadOneofValue = false if let current = self.operation { @@ -6102,7 +5794,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmPromotef32Tof64(v) } }() - case 228: try { + case 214: try { var v: Fuzzilli_Protobuf_WasmReinterpretf32Asi32? var hadOneofValue = false if let current = self.operation { @@ -6115,7 +5807,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpretf32Asi32(v) } }() - case 229: try { + case 215: try { var v: Fuzzilli_Protobuf_WasmReinterpretf64Asi64? var hadOneofValue = false if let current = self.operation { @@ -6128,7 +5820,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpretf64Asi64(v) } }() - case 230: try { + case 216: try { var v: Fuzzilli_Protobuf_WasmReinterpreti32Asf32? var hadOneofValue = false if let current = self.operation { @@ -6141,7 +5833,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpreti32Asf32(v) } }() - case 231: try { + case 217: try { var v: Fuzzilli_Protobuf_WasmReinterpreti64Asf64? var hadOneofValue = false if let current = self.operation { @@ -6154,7 +5846,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpreti64Asf64(v) } }() - case 232: try { + case 218: try { var v: Fuzzilli_Protobuf_WasmSignExtend8Intoi32? var hadOneofValue = false if let current = self.operation { @@ -6167,7 +5859,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend8Intoi32(v) } }() - case 233: try { + case 219: try { var v: Fuzzilli_Protobuf_WasmSignExtend16Intoi32? var hadOneofValue = false if let current = self.operation { @@ -6180,7 +5872,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend16Intoi32(v) } }() - case 234: try { + case 220: try { var v: Fuzzilli_Protobuf_WasmSignExtend8Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6193,7 +5885,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend8Intoi64(v) } }() - case 235: try { + case 221: try { var v: Fuzzilli_Protobuf_WasmSignExtend16Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6206,7 +5898,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend16Intoi64(v) } }() - case 236: try { + case 222: try { var v: Fuzzilli_Protobuf_WasmSignExtend32Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6219,7 +5911,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend32Intoi64(v) } }() - case 237: try { + case 223: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf32Toi32? var hadOneofValue = false if let current = self.operation { @@ -6232,7 +5924,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf32Toi32(v) } }() - case 238: try { + case 224: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf64Toi32? var hadOneofValue = false if let current = self.operation { @@ -6245,7 +5937,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf64Toi32(v) } }() - case 239: try { + case 225: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf32Toi64? var hadOneofValue = false if let current = self.operation { @@ -6258,7 +5950,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf32Toi64(v) } }() - case 240: try { + case 226: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf64Toi64? var hadOneofValue = false if let current = self.operation { @@ -6271,7 +5963,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf64Toi64(v) } }() - case 241: try { + case 227: try { var v: Fuzzilli_Protobuf_WasmReassign? var hadOneofValue = false if let current = self.operation { @@ -6284,7 +5976,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReassign(v) } }() - case 242: try { + case 228: try { var v: Fuzzilli_Protobuf_WasmDefineGlobal? var hadOneofValue = false if let current = self.operation { @@ -6297,7 +5989,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineGlobal(v) } }() - case 243: try { + case 229: try { var v: Fuzzilli_Protobuf_WasmDefineTable? var hadOneofValue = false if let current = self.operation { @@ -6310,7 +6002,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineTable(v) } }() - case 244: try { + case 230: try { var v: Fuzzilli_Protobuf_WasmDefineMemory? var hadOneofValue = false if let current = self.operation { @@ -6323,7 +6015,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineMemory(v) } }() - case 245: try { + case 231: try { var v: Fuzzilli_Protobuf_WasmDefineDataSegment? var hadOneofValue = false if let current = self.operation { @@ -6336,7 +6028,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineDataSegment(v) } }() - case 246: try { + case 232: try { var v: Fuzzilli_Protobuf_WasmLoadGlobal? var hadOneofValue = false if let current = self.operation { @@ -6349,7 +6041,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmLoadGlobal(v) } }() - case 247: try { + case 233: try { var v: Fuzzilli_Protobuf_WasmStoreGlobal? var hadOneofValue = false if let current = self.operation { @@ -6362,7 +6054,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStoreGlobal(v) } }() - case 248: try { + case 234: try { var v: Fuzzilli_Protobuf_WasmTableGet? var hadOneofValue = false if let current = self.operation { @@ -6375,7 +6067,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableGet(v) } }() - case 249: try { + case 235: try { var v: Fuzzilli_Protobuf_WasmTableSet? var hadOneofValue = false if let current = self.operation { @@ -6388,7 +6080,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableSet(v) } }() - case 250: try { + case 236: try { var v: Fuzzilli_Protobuf_WasmTableSize? var hadOneofValue = false if let current = self.operation { @@ -6401,7 +6093,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableSize(v) } }() - case 251: try { + case 237: try { var v: Fuzzilli_Protobuf_WasmTableGrow? var hadOneofValue = false if let current = self.operation { @@ -6414,7 +6106,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableGrow(v) } }() - case 252: try { + case 238: try { var v: Fuzzilli_Protobuf_WasmCallIndirect? var hadOneofValue = false if let current = self.operation { @@ -6427,7 +6119,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmCallIndirect(v) } }() - case 253: try { + case 239: try { var v: Fuzzilli_Protobuf_WasmCallDirect? var hadOneofValue = false if let current = self.operation { @@ -6440,7 +6132,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmCallDirect(v) } }() - case 254: try { + case 240: try { var v: Fuzzilli_Protobuf_WasmReturnCallDirect? var hadOneofValue = false if let current = self.operation { @@ -6453,7 +6145,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturnCallDirect(v) } }() - case 255: try { + case 241: try { var v: Fuzzilli_Protobuf_WasmReturnCallIndirect? var hadOneofValue = false if let current = self.operation { @@ -6466,7 +6158,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturnCallIndirect(v) } }() - case 256: try { + case 242: try { var v: Fuzzilli_Protobuf_WasmMemoryLoad? var hadOneofValue = false if let current = self.operation { @@ -6479,7 +6171,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryLoad(v) } }() - case 257: try { + case 243: try { var v: Fuzzilli_Protobuf_WasmMemoryStore? var hadOneofValue = false if let current = self.operation { @@ -6492,7 +6184,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryStore(v) } }() - case 258: try { + case 244: try { var v: Fuzzilli_Protobuf_WasmAtomicLoad? var hadOneofValue = false if let current = self.operation { @@ -6505,7 +6197,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicLoad(v) } }() - case 259: try { + case 245: try { var v: Fuzzilli_Protobuf_WasmAtomicStore? var hadOneofValue = false if let current = self.operation { @@ -6518,7 +6210,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicStore(v) } }() - case 260: try { + case 246: try { var v: Fuzzilli_Protobuf_WasmAtomicRMW? var hadOneofValue = false if let current = self.operation { @@ -6531,7 +6223,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicRmw(v) } }() - case 261: try { + case 247: try { var v: Fuzzilli_Protobuf_WasmAtomicCmpxchg? var hadOneofValue = false if let current = self.operation { @@ -6544,7 +6236,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicCmpxchg(v) } }() - case 262: try { + case 248: try { var v: Fuzzilli_Protobuf_WasmMemorySize? var hadOneofValue = false if let current = self.operation { @@ -6557,7 +6249,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemorySize(v) } }() - case 263: try { + case 249: try { var v: Fuzzilli_Protobuf_WasmMemoryGrow? var hadOneofValue = false if let current = self.operation { @@ -6570,7 +6262,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryGrow(v) } }() - case 264: try { + case 250: try { var v: Fuzzilli_Protobuf_WasmMemoryFill? var hadOneofValue = false if let current = self.operation { @@ -6583,7 +6275,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryFill(v) } }() - case 265: try { + case 251: try { var v: Fuzzilli_Protobuf_WasmMemoryInit? var hadOneofValue = false if let current = self.operation { @@ -6596,7 +6288,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryInit(v) } }() - case 266: try { + case 252: try { var v: Fuzzilli_Protobuf_WasmDropDataSegment? var hadOneofValue = false if let current = self.operation { @@ -6609,7 +6301,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDropDataSegment(v) } }() - case 267: try { + case 253: try { var v: Fuzzilli_Protobuf_BeginWasmFunction? var hadOneofValue = false if let current = self.operation { @@ -6622,7 +6314,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWasmFunction(v) } }() - case 268: try { + case 254: try { var v: Fuzzilli_Protobuf_EndWasmFunction? var hadOneofValue = false if let current = self.operation { @@ -6635,7 +6327,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWasmFunction(v) } }() - case 269: try { + case 255: try { var v: Fuzzilli_Protobuf_WasmBeginBlock? var hadOneofValue = false if let current = self.operation { @@ -6648,7 +6340,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginBlock(v) } }() - case 270: try { + case 256: try { var v: Fuzzilli_Protobuf_WasmEndBlock? var hadOneofValue = false if let current = self.operation { @@ -6661,7 +6353,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndBlock(v) } }() - case 271: try { + case 257: try { var v: Fuzzilli_Protobuf_WasmBeginLoop? var hadOneofValue = false if let current = self.operation { @@ -6674,7 +6366,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginLoop(v) } }() - case 272: try { + case 258: try { var v: Fuzzilli_Protobuf_WasmEndLoop? var hadOneofValue = false if let current = self.operation { @@ -6687,7 +6379,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndLoop(v) } }() - case 273: try { + case 259: try { var v: Fuzzilli_Protobuf_WasmBranch? var hadOneofValue = false if let current = self.operation { @@ -6700,7 +6392,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranch(v) } }() - case 274: try { + case 260: try { var v: Fuzzilli_Protobuf_WasmBranchIf? var hadOneofValue = false if let current = self.operation { @@ -6713,7 +6405,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranchIf(v) } }() - case 275: try { + case 261: try { var v: Fuzzilli_Protobuf_WasmBranchTable? var hadOneofValue = false if let current = self.operation { @@ -6726,7 +6418,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranchTable(v) } }() - case 276: try { + case 262: try { var v: Fuzzilli_Protobuf_WasmNop? var hadOneofValue = false if let current = self.operation { @@ -6739,7 +6431,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmNop(v) } }() - case 277: try { + case 263: try { var v: Fuzzilli_Protobuf_WasmBeginIf? var hadOneofValue = false if let current = self.operation { @@ -6752,7 +6444,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginIf(v) } }() - case 278: try { + case 264: try { var v: Fuzzilli_Protobuf_WasmBeginElse? var hadOneofValue = false if let current = self.operation { @@ -6765,7 +6457,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginElse(v) } }() - case 279: try { + case 265: try { var v: Fuzzilli_Protobuf_WasmEndIf? var hadOneofValue = false if let current = self.operation { @@ -6778,7 +6470,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndIf(v) } }() - case 280: try { + case 266: try { var v: Fuzzilli_Protobuf_WasmBeginTryTable? var hadOneofValue = false if let current = self.operation { @@ -6791,7 +6483,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTryTable(v) } }() - case 281: try { + case 267: try { var v: Fuzzilli_Protobuf_WasmEndTryTable? var hadOneofValue = false if let current = self.operation { @@ -6804,7 +6496,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTryTable(v) } }() - case 282: try { + case 268: try { var v: Fuzzilli_Protobuf_WasmBeginTry? var hadOneofValue = false if let current = self.operation { @@ -6817,7 +6509,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTry(v) } }() - case 283: try { + case 269: try { var v: Fuzzilli_Protobuf_WasmBeginCatchAll? var hadOneofValue = false if let current = self.operation { @@ -6830,7 +6522,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginCatchAll(v) } }() - case 284: try { + case 270: try { var v: Fuzzilli_Protobuf_WasmBeginCatch? var hadOneofValue = false if let current = self.operation { @@ -6843,7 +6535,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginCatch(v) } }() - case 285: try { + case 271: try { var v: Fuzzilli_Protobuf_WasmEndTry? var hadOneofValue = false if let current = self.operation { @@ -6856,7 +6548,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTry(v) } }() - case 286: try { + case 272: try { var v: Fuzzilli_Protobuf_WasmBeginTryDelegate? var hadOneofValue = false if let current = self.operation { @@ -6869,7 +6561,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTryDelegate(v) } }() - case 287: try { + case 273: try { var v: Fuzzilli_Protobuf_WasmEndTryDelegate? var hadOneofValue = false if let current = self.operation { @@ -6882,7 +6574,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTryDelegate(v) } }() - case 288: try { + case 274: try { var v: Fuzzilli_Protobuf_WasmThrow? var hadOneofValue = false if let current = self.operation { @@ -6895,7 +6587,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmThrow(v) } }() - case 289: try { + case 275: try { var v: Fuzzilli_Protobuf_WasmRethrow? var hadOneofValue = false if let current = self.operation { @@ -6908,7 +6600,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRethrow(v) } }() - case 290: try { + case 276: try { var v: Fuzzilli_Protobuf_WasmThrowRef? var hadOneofValue = false if let current = self.operation { @@ -6921,7 +6613,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmThrowRef(v) } }() - case 291: try { + case 277: try { var v: Fuzzilli_Protobuf_WasmDefineTag? var hadOneofValue = false if let current = self.operation { @@ -6934,7 +6626,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineTag(v) } }() - case 292: try { + case 278: try { var v: Fuzzilli_Protobuf_ConstSimd128? var hadOneofValue = false if let current = self.operation { @@ -6947,7 +6639,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constSimd128(v) } }() - case 293: try { + case 279: try { var v: Fuzzilli_Protobuf_WasmSimd128Compare? var hadOneofValue = false if let current = self.operation { @@ -6960,7 +6652,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128Compare(v) } }() - case 294: try { + case 280: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerUnOp? var hadOneofValue = false if let current = self.operation { @@ -6973,7 +6665,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerUnOp(v) } }() - case 295: try { + case 281: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerBinOp? var hadOneofValue = false if let current = self.operation { @@ -6986,7 +6678,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerBinOp(v) } }() - case 296: try { + case 282: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp? var hadOneofValue = false if let current = self.operation { @@ -6999,7 +6691,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerTernaryOp(v) } }() - case 297: try { + case 283: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatUnOp? var hadOneofValue = false if let current = self.operation { @@ -7012,7 +6704,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatUnOp(v) } }() - case 298: try { + case 284: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatBinOp? var hadOneofValue = false if let current = self.operation { @@ -7025,7 +6717,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatBinOp(v) } }() - case 299: try { + case 285: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatTernaryOp? var hadOneofValue = false if let current = self.operation { @@ -7038,7 +6730,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatTernaryOp(v) } }() - case 300: try { + case 286: try { var v: Fuzzilli_Protobuf_WasmSimdSplat? var hadOneofValue = false if let current = self.operation { @@ -7051,7 +6743,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdSplat(v) } }() - case 301: try { + case 287: try { var v: Fuzzilli_Protobuf_WasmSimdExtractLane? var hadOneofValue = false if let current = self.operation { @@ -7064,7 +6756,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdExtractLane(v) } }() - case 302: try { + case 288: try { var v: Fuzzilli_Protobuf_WasmSimdReplaceLane? var hadOneofValue = false if let current = self.operation { @@ -7077,7 +6769,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdReplaceLane(v) } }() - case 303: try { + case 289: try { var v: Fuzzilli_Protobuf_WasmSimdStoreLane? var hadOneofValue = false if let current = self.operation { @@ -7090,7 +6782,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdStoreLane(v) } }() - case 304: try { + case 290: try { var v: Fuzzilli_Protobuf_WasmSimdLoadLane? var hadOneofValue = false if let current = self.operation { @@ -7103,7 +6795,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdLoadLane(v) } }() - case 305: try { + case 291: try { var v: Fuzzilli_Protobuf_WasmSimdLoad? var hadOneofValue = false if let current = self.operation { @@ -7116,7 +6808,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdLoad(v) } }() - case 306: try { + case 292: try { var v: Fuzzilli_Protobuf_WasmUnreachable? var hadOneofValue = false if let current = self.operation { @@ -7129,7 +6821,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmUnreachable(v) } }() - case 307: try { + case 293: try { var v: Fuzzilli_Protobuf_WasmSelect? var hadOneofValue = false if let current = self.operation { @@ -7142,7 +6834,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSelect(v) } }() - case 308: try { + case 294: try { var v: Fuzzilli_Protobuf_WasmBeginTypeGroup? var hadOneofValue = false if let current = self.operation { @@ -7155,7 +6847,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTypeGroup(v) } }() - case 309: try { + case 295: try { var v: Fuzzilli_Protobuf_WasmEndTypeGroup? var hadOneofValue = false if let current = self.operation { @@ -7168,7 +6860,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTypeGroup(v) } }() - case 310: try { + case 296: try { var v: Fuzzilli_Protobuf_WasmDefineArrayType? var hadOneofValue = false if let current = self.operation { @@ -7181,7 +6873,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineArrayType(v) } }() - case 311: try { + case 297: try { var v: Fuzzilli_Protobuf_WasmDefineStructType? var hadOneofValue = false if let current = self.operation { @@ -7194,7 +6886,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineStructType(v) } }() - case 312: try { + case 298: try { var v: Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference? var hadOneofValue = false if let current = self.operation { @@ -7207,7 +6899,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineForwardOrSelfReference(v) } }() - case 313: try { + case 299: try { var v: Fuzzilli_Protobuf_WasmResolveForwardReference? var hadOneofValue = false if let current = self.operation { @@ -7220,7 +6912,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmResolveForwardReference(v) } }() - case 314: try { + case 300: try { var v: Fuzzilli_Protobuf_WasmArrayNewFixed? var hadOneofValue = false if let current = self.operation { @@ -7233,7 +6925,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayNewFixed(v) } }() - case 315: try { + case 301: try { var v: Fuzzilli_Protobuf_WasmArrayNewDefault? var hadOneofValue = false if let current = self.operation { @@ -7246,7 +6938,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayNewDefault(v) } }() - case 316: try { + case 302: try { var v: Fuzzilli_Protobuf_WasmArrayLen? var hadOneofValue = false if let current = self.operation { @@ -7259,7 +6951,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayLen(v) } }() - case 317: try { + case 303: try { var v: Fuzzilli_Protobuf_WasmArrayGet? var hadOneofValue = false if let current = self.operation { @@ -7272,7 +6964,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayGet(v) } }() - case 318: try { + case 304: try { var v: Fuzzilli_Protobuf_WasmArraySet? var hadOneofValue = false if let current = self.operation { @@ -7285,7 +6977,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArraySet(v) } }() - case 319: try { + case 305: try { var v: Fuzzilli_Protobuf_WasmStructNewDefault? var hadOneofValue = false if let current = self.operation { @@ -7298,7 +6990,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructNewDefault(v) } }() - case 320: try { + case 306: try { var v: Fuzzilli_Protobuf_WasmStructGet? var hadOneofValue = false if let current = self.operation { @@ -7311,7 +7003,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructGet(v) } }() - case 321: try { + case 307: try { var v: Fuzzilli_Protobuf_WasmStructSet? var hadOneofValue = false if let current = self.operation { @@ -7324,7 +7016,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructSet(v) } }() - case 322: try { + case 308: try { var v: Fuzzilli_Protobuf_WasmRefNull? var hadOneofValue = false if let current = self.operation { @@ -7337,7 +7029,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefNull(v) } }() - case 323: try { + case 309: try { var v: Fuzzilli_Protobuf_WasmRefIsNull? var hadOneofValue = false if let current = self.operation { @@ -7350,7 +7042,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefIsNull(v) } }() - case 324: try { + case 310: try { var v: Fuzzilli_Protobuf_WasmRefI31? var hadOneofValue = false if let current = self.operation { @@ -7363,7 +7055,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefI31(v) } }() - case 325: try { + case 311: try { var v: Fuzzilli_Protobuf_WasmI31Get? var hadOneofValue = false if let current = self.operation { @@ -7376,7 +7068,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmI31Get(v) } }() - case 326: try { + case 312: try { var v: Fuzzilli_Protobuf_WasmAnyConvertExtern? var hadOneofValue = false if let current = self.operation { @@ -7389,7 +7081,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAnyConvertExtern(v) } }() - case 327: try { + case 313: try { var v: Fuzzilli_Protobuf_WasmExternConvertAny? var hadOneofValue = false if let current = self.operation { @@ -7402,7 +7094,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmExternConvertAny(v) } }() - case 328: try { + case 314: try { var v: Fuzzilli_Protobuf_WasmMemoryCopy? var hadOneofValue = false if let current = self.operation { @@ -7415,7 +7107,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryCopy(v) } }() - case 329: try { + case 315: try { var v: Fuzzilli_Protobuf_WasmDefineElementSegment? var hadOneofValue = false if let current = self.operation { @@ -7428,7 +7120,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineElementSegment(v) } }() - case 330: try { + case 316: try { var v: Fuzzilli_Protobuf_WasmTableInit? var hadOneofValue = false if let current = self.operation { @@ -7441,7 +7133,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableInit(v) } }() - case 331: try { + case 317: try { var v: Fuzzilli_Protobuf_WasmDropElementSegment? var hadOneofValue = false if let current = self.operation { @@ -7454,7 +7146,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDropElementSegment(v) } }() - case 332: try { + case 318: try { var v: Fuzzilli_Protobuf_WasmTableCopy? var hadOneofValue = false if let current = self.operation { @@ -7467,7 +7159,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableCopy(v) } }() - case 333: try { + case 319: try { var v: Fuzzilli_Protobuf_WasmDefineSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7480,7 +7172,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineSignatureType(v) } }() - case 334: try { + case 320: try { var v: Fuzzilli_Protobuf_CreateNamedDisposableVariable? var hadOneofValue = false if let current = self.operation { @@ -7493,7 +7185,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedDisposableVariable(v) } }() - case 335: try { + case 321: try { var v: Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable? var hadOneofValue = false if let current = self.operation { @@ -7506,7 +7198,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedAsyncDisposableVariable(v) } }() - case 336: try { + case 322: try { var v: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7519,7 +7211,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocSignatureType(v) } }() - case 337: try { + case 323: try { var v: Fuzzilli_Protobuf_WasmStructNew? var hadOneofValue = false if let current = self.operation { @@ -7532,7 +7224,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructNew(v) } }() - case 338: try { + case 324: try { var v: Fuzzilli_Protobuf_WasmRefEq? var hadOneofValue = false if let current = self.operation { @@ -7545,7 +7237,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefEq(v) } }() - case 339: try { + case 325: try { var v: Fuzzilli_Protobuf_WasmRefTest? var hadOneofValue = false if let current = self.operation { @@ -7558,7 +7250,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefTest(v) } }() - case 340: try { + case 326: try { var v: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7571,7 +7263,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocModuleSignatureType(v) } }() - case 341: try { + case 327: try { var v: Fuzzilli_Protobuf_WasmRefCast? var hadOneofValue = false if let current = self.operation { @@ -7730,1233 +7422,1177 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endClassConstructor(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 34) }() - case .classAddInstanceProperty?: try { - guard case .classAddInstanceProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddProperty?: try { + guard case .classAddProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 35) }() - case .classAddInstanceElement?: try { - guard case .classAddInstanceElement(let v)? = self.operation else { preconditionFailure() } + case .classAddElement?: try { + guard case .classAddElement(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 36) }() - case .classAddInstanceComputedProperty?: try { - guard case .classAddInstanceComputedProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddComputedProperty?: try { + guard case .classAddComputedProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 37) }() - case .beginClassInstanceMethod?: try { - guard case .beginClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } + case .beginClassMethod?: try { + guard case .beginClassMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 38) }() - case .endClassInstanceMethod?: try { - guard case .endClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } + case .endClassMethod?: try { + guard case .endClassMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 39) }() - case .beginClassInstanceComputedMethod?: try { - guard case .beginClassInstanceComputedMethod(let v)? = self.operation else { preconditionFailure() } + case .beginClassComputedMethod?: try { + guard case .beginClassComputedMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 40) }() - case .endClassInstanceComputedMethod?: try { - guard case .endClassInstanceComputedMethod(let v)? = self.operation else { preconditionFailure() } + case .endClassComputedMethod?: try { + guard case .endClassComputedMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 41) }() - case .beginClassInstanceGetter?: try { - guard case .beginClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } + case .beginClassGetter?: try { + guard case .beginClassGetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 42) }() - case .endClassInstanceGetter?: try { - guard case .endClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } + case .endClassGetter?: try { + guard case .endClassGetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 43) }() - case .beginClassInstanceSetter?: try { - guard case .beginClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } + case .beginClassSetter?: try { + guard case .beginClassSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 44) }() - case .endClassInstanceSetter?: try { - guard case .endClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } + case .endClassSetter?: try { + guard case .endClassSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 45) }() - case .classAddStaticProperty?: try { - guard case .classAddStaticProperty(let v)? = self.operation else { preconditionFailure() } + case .beginClassStaticInitializer?: try { + guard case .beginClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 46) }() - case .classAddStaticElement?: try { - guard case .classAddStaticElement(let v)? = self.operation else { preconditionFailure() } + case .endClassStaticInitializer?: try { + guard case .endClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 47) }() - case .classAddStaticComputedProperty?: try { - guard case .classAddStaticComputedProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddPrivateProperty?: try { + guard case .classAddPrivateProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 48) }() - case .beginClassStaticInitializer?: try { - guard case .beginClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } + case .beginClassPrivateMethod?: try { + guard case .beginClassPrivateMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 49) }() - case .endClassStaticInitializer?: try { - guard case .endClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } + case .endClassPrivateMethod?: try { + guard case .endClassPrivateMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 50) }() - case .beginClassStaticMethod?: try { - guard case .beginClassStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 51) - }() - case .endClassStaticMethod?: try { - guard case .endClassStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 52) - }() - case .beginClassStaticComputedMethod?: try { - guard case .beginClassStaticComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 53) - }() - case .endClassStaticComputedMethod?: try { - guard case .endClassStaticComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 54) - }() - case .beginClassStaticGetter?: try { - guard case .beginClassStaticGetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 55) - }() - case .endClassStaticGetter?: try { - guard case .endClassStaticGetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 56) - }() - case .beginClassStaticSetter?: try { - guard case .beginClassStaticSetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 57) - }() - case .endClassStaticSetter?: try { - guard case .endClassStaticSetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 58) - }() - case .classAddPrivateInstanceProperty?: try { - guard case .classAddPrivateInstanceProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 59) - }() - case .beginClassPrivateInstanceMethod?: try { - guard case .beginClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 60) - }() - case .endClassPrivateInstanceMethod?: try { - guard case .endClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 61) - }() - case .classAddPrivateStaticProperty?: try { - guard case .classAddPrivateStaticProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 62) - }() - case .beginClassPrivateStaticMethod?: try { - guard case .beginClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 63) - }() - case .endClassPrivateStaticMethod?: try { - guard case .endClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 64) - }() case .endClassDefinition?: try { guard case .endClassDefinition(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 65) + try visitor.visitSingularMessageField(value: v, fieldNumber: 51) }() case .createArray?: try { guard case .createArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 66) + try visitor.visitSingularMessageField(value: v, fieldNumber: 52) }() case .createIntArray?: try { guard case .createIntArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 67) + try visitor.visitSingularMessageField(value: v, fieldNumber: 53) }() case .createFloatArray?: try { guard case .createFloatArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 68) + try visitor.visitSingularMessageField(value: v, fieldNumber: 54) }() case .createArrayWithSpread?: try { guard case .createArrayWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 69) + try visitor.visitSingularMessageField(value: v, fieldNumber: 55) }() case .createTemplateString?: try { guard case .createTemplateString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 70) + try visitor.visitSingularMessageField(value: v, fieldNumber: 56) }() case .getProperty?: try { guard case .getProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 71) + try visitor.visitSingularMessageField(value: v, fieldNumber: 57) }() case .setProperty?: try { guard case .setProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 72) + try visitor.visitSingularMessageField(value: v, fieldNumber: 58) }() case .updateProperty?: try { guard case .updateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 73) + try visitor.visitSingularMessageField(value: v, fieldNumber: 59) }() case .deleteProperty?: try { guard case .deleteProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 74) + try visitor.visitSingularMessageField(value: v, fieldNumber: 60) }() case .configureProperty?: try { guard case .configureProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 75) + try visitor.visitSingularMessageField(value: v, fieldNumber: 61) }() case .getElement?: try { guard case .getElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 76) + try visitor.visitSingularMessageField(value: v, fieldNumber: 62) }() case .setElement?: try { guard case .setElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 77) + try visitor.visitSingularMessageField(value: v, fieldNumber: 63) }() case .updateElement?: try { guard case .updateElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 78) + try visitor.visitSingularMessageField(value: v, fieldNumber: 64) }() case .deleteElement?: try { guard case .deleteElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 79) + try visitor.visitSingularMessageField(value: v, fieldNumber: 65) }() case .configureElement?: try { guard case .configureElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 80) + try visitor.visitSingularMessageField(value: v, fieldNumber: 66) }() case .getComputedProperty?: try { guard case .getComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 81) + try visitor.visitSingularMessageField(value: v, fieldNumber: 67) }() case .setComputedProperty?: try { guard case .setComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 82) + try visitor.visitSingularMessageField(value: v, fieldNumber: 68) }() case .updateComputedProperty?: try { guard case .updateComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 83) + try visitor.visitSingularMessageField(value: v, fieldNumber: 69) }() case .deleteComputedProperty?: try { guard case .deleteComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 84) + try visitor.visitSingularMessageField(value: v, fieldNumber: 70) }() case .configureComputedProperty?: try { guard case .configureComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 85) + try visitor.visitSingularMessageField(value: v, fieldNumber: 71) }() case .typeOf?: try { guard case .typeOf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 86) + try visitor.visitSingularMessageField(value: v, fieldNumber: 72) }() case .void?: try { guard case .void(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 87) + try visitor.visitSingularMessageField(value: v, fieldNumber: 73) }() case .testInstanceOf?: try { guard case .testInstanceOf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 88) + try visitor.visitSingularMessageField(value: v, fieldNumber: 74) }() case .testIn?: try { guard case .testIn(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 89) + try visitor.visitSingularMessageField(value: v, fieldNumber: 75) }() case .beginPlainFunction?: try { guard case .beginPlainFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 90) + try visitor.visitSingularMessageField(value: v, fieldNumber: 76) }() case .endPlainFunction?: try { guard case .endPlainFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 91) + try visitor.visitSingularMessageField(value: v, fieldNumber: 77) }() case .beginArrowFunction?: try { guard case .beginArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 92) + try visitor.visitSingularMessageField(value: v, fieldNumber: 78) }() case .endArrowFunction?: try { guard case .endArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 93) + try visitor.visitSingularMessageField(value: v, fieldNumber: 79) }() case .beginGeneratorFunction?: try { guard case .beginGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 94) + try visitor.visitSingularMessageField(value: v, fieldNumber: 80) }() case .endGeneratorFunction?: try { guard case .endGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 95) + try visitor.visitSingularMessageField(value: v, fieldNumber: 81) }() case .beginAsyncFunction?: try { guard case .beginAsyncFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 96) + try visitor.visitSingularMessageField(value: v, fieldNumber: 82) }() case .endAsyncFunction?: try { guard case .endAsyncFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 97) + try visitor.visitSingularMessageField(value: v, fieldNumber: 83) }() case .beginAsyncArrowFunction?: try { guard case .beginAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 98) + try visitor.visitSingularMessageField(value: v, fieldNumber: 84) }() case .endAsyncArrowFunction?: try { guard case .endAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 99) + try visitor.visitSingularMessageField(value: v, fieldNumber: 85) }() case .beginAsyncGeneratorFunction?: try { guard case .beginAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 100) + try visitor.visitSingularMessageField(value: v, fieldNumber: 86) }() case .endAsyncGeneratorFunction?: try { guard case .endAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 101) + try visitor.visitSingularMessageField(value: v, fieldNumber: 87) }() case .beginConstructor?: try { guard case .beginConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 102) + try visitor.visitSingularMessageField(value: v, fieldNumber: 88) }() case .endConstructor?: try { guard case .endConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 103) + try visitor.visitSingularMessageField(value: v, fieldNumber: 89) }() case .directive?: try { guard case .directive(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 104) + try visitor.visitSingularMessageField(value: v, fieldNumber: 90) }() case .return?: try { guard case .return(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 105) + try visitor.visitSingularMessageField(value: v, fieldNumber: 91) }() case .yield?: try { guard case .yield(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 106) + try visitor.visitSingularMessageField(value: v, fieldNumber: 92) }() case .yieldEach?: try { guard case .yieldEach(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 107) + try visitor.visitSingularMessageField(value: v, fieldNumber: 93) }() case .await?: try { guard case .await(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 108) + try visitor.visitSingularMessageField(value: v, fieldNumber: 94) }() case .callFunction?: try { guard case .callFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 109) + try visitor.visitSingularMessageField(value: v, fieldNumber: 95) }() case .callFunctionWithSpread?: try { guard case .callFunctionWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 110) + try visitor.visitSingularMessageField(value: v, fieldNumber: 96) }() case .construct?: try { guard case .construct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 111) + try visitor.visitSingularMessageField(value: v, fieldNumber: 97) }() case .constructWithSpread?: try { guard case .constructWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 112) + try visitor.visitSingularMessageField(value: v, fieldNumber: 98) }() case .callMethod?: try { guard case .callMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 113) + try visitor.visitSingularMessageField(value: v, fieldNumber: 99) }() case .callMethodWithSpread?: try { guard case .callMethodWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 114) + try visitor.visitSingularMessageField(value: v, fieldNumber: 100) }() case .callComputedMethod?: try { guard case .callComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 115) + try visitor.visitSingularMessageField(value: v, fieldNumber: 101) }() case .callComputedMethodWithSpread?: try { guard case .callComputedMethodWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 116) + try visitor.visitSingularMessageField(value: v, fieldNumber: 102) }() case .unaryOperation?: try { guard case .unaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 117) + try visitor.visitSingularMessageField(value: v, fieldNumber: 103) }() case .binaryOperation?: try { guard case .binaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 118) + try visitor.visitSingularMessageField(value: v, fieldNumber: 104) }() case .ternaryOperation?: try { guard case .ternaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 119) + try visitor.visitSingularMessageField(value: v, fieldNumber: 105) }() case .update?: try { guard case .update(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 120) + try visitor.visitSingularMessageField(value: v, fieldNumber: 106) }() case .dup?: try { guard case .dup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 121) + try visitor.visitSingularMessageField(value: v, fieldNumber: 107) }() case .reassign?: try { guard case .reassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 122) + try visitor.visitSingularMessageField(value: v, fieldNumber: 108) }() case .destructArray?: try { guard case .destructArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 123) + try visitor.visitSingularMessageField(value: v, fieldNumber: 109) }() case .destructArrayAndReassign?: try { guard case .destructArrayAndReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 124) + try visitor.visitSingularMessageField(value: v, fieldNumber: 110) }() case .destructObject?: try { guard case .destructObject(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 125) + try visitor.visitSingularMessageField(value: v, fieldNumber: 111) }() case .destructObjectAndReassign?: try { guard case .destructObjectAndReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 126) + try visitor.visitSingularMessageField(value: v, fieldNumber: 112) }() case .compare?: try { guard case .compare(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 127) + try visitor.visitSingularMessageField(value: v, fieldNumber: 113) }() case .eval?: try { guard case .eval(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 128) + try visitor.visitSingularMessageField(value: v, fieldNumber: 114) }() case .beginWith?: try { guard case .beginWith(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 129) + try visitor.visitSingularMessageField(value: v, fieldNumber: 115) }() case .endWith?: try { guard case .endWith(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 130) + try visitor.visitSingularMessageField(value: v, fieldNumber: 116) }() case .callSuperConstructor?: try { guard case .callSuperConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 131) + try visitor.visitSingularMessageField(value: v, fieldNumber: 117) }() case .callSuperMethod?: try { guard case .callSuperMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 132) + try visitor.visitSingularMessageField(value: v, fieldNumber: 118) }() case .getPrivateProperty?: try { guard case .getPrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 133) + try visitor.visitSingularMessageField(value: v, fieldNumber: 119) }() case .setPrivateProperty?: try { guard case .setPrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 134) + try visitor.visitSingularMessageField(value: v, fieldNumber: 120) }() case .updatePrivateProperty?: try { guard case .updatePrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 135) + try visitor.visitSingularMessageField(value: v, fieldNumber: 121) }() case .callPrivateMethod?: try { guard case .callPrivateMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 136) + try visitor.visitSingularMessageField(value: v, fieldNumber: 122) }() case .getSuperProperty?: try { guard case .getSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 137) + try visitor.visitSingularMessageField(value: v, fieldNumber: 123) }() case .setSuperProperty?: try { guard case .setSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 138) + try visitor.visitSingularMessageField(value: v, fieldNumber: 124) }() case .getComputedSuperProperty?: try { guard case .getComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 139) + try visitor.visitSingularMessageField(value: v, fieldNumber: 125) }() case .setComputedSuperProperty?: try { guard case .setComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 140) + try visitor.visitSingularMessageField(value: v, fieldNumber: 126) }() case .updateSuperProperty?: try { guard case .updateSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 141) + try visitor.visitSingularMessageField(value: v, fieldNumber: 127) }() case .beginIf?: try { guard case .beginIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 142) + try visitor.visitSingularMessageField(value: v, fieldNumber: 128) }() case .beginElse?: try { guard case .beginElse(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 143) + try visitor.visitSingularMessageField(value: v, fieldNumber: 129) }() case .endIf?: try { guard case .endIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 144) + try visitor.visitSingularMessageField(value: v, fieldNumber: 130) }() case .beginWhileLoopHeader?: try { guard case .beginWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 145) + try visitor.visitSingularMessageField(value: v, fieldNumber: 131) }() case .beginWhileLoopBody?: try { guard case .beginWhileLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 146) + try visitor.visitSingularMessageField(value: v, fieldNumber: 132) }() case .endWhileLoop?: try { guard case .endWhileLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 147) + try visitor.visitSingularMessageField(value: v, fieldNumber: 133) }() case .beginDoWhileLoopBody?: try { guard case .beginDoWhileLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 148) + try visitor.visitSingularMessageField(value: v, fieldNumber: 134) }() case .beginDoWhileLoopHeader?: try { guard case .beginDoWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 149) + try visitor.visitSingularMessageField(value: v, fieldNumber: 135) }() case .endDoWhileLoop?: try { guard case .endDoWhileLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 150) + try visitor.visitSingularMessageField(value: v, fieldNumber: 136) }() case .beginForLoopInitializer?: try { guard case .beginForLoopInitializer(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 151) + try visitor.visitSingularMessageField(value: v, fieldNumber: 137) }() case .beginForLoopCondition?: try { guard case .beginForLoopCondition(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 152) + try visitor.visitSingularMessageField(value: v, fieldNumber: 138) }() case .beginForLoopAfterthought?: try { guard case .beginForLoopAfterthought(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 153) + try visitor.visitSingularMessageField(value: v, fieldNumber: 139) }() case .beginForLoopBody?: try { guard case .beginForLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 154) + try visitor.visitSingularMessageField(value: v, fieldNumber: 140) }() case .endForLoop?: try { guard case .endForLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + try visitor.visitSingularMessageField(value: v, fieldNumber: 141) }() case .beginForInLoop?: try { guard case .beginForInLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 156) + try visitor.visitSingularMessageField(value: v, fieldNumber: 142) }() case .endForInLoop?: try { guard case .endForInLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 157) + try visitor.visitSingularMessageField(value: v, fieldNumber: 143) }() case .beginForOfLoop?: try { guard case .beginForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 158) + try visitor.visitSingularMessageField(value: v, fieldNumber: 144) }() case .beginForOfLoopWithDestruct?: try { guard case .beginForOfLoopWithDestruct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 159) + try visitor.visitSingularMessageField(value: v, fieldNumber: 145) }() case .endForOfLoop?: try { guard case .endForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 160) + try visitor.visitSingularMessageField(value: v, fieldNumber: 146) }() case .beginRepeatLoop?: try { guard case .beginRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 161) + try visitor.visitSingularMessageField(value: v, fieldNumber: 147) }() case .endRepeatLoop?: try { guard case .endRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 162) + try visitor.visitSingularMessageField(value: v, fieldNumber: 148) }() case .loopBreak?: try { guard case .loopBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 163) + try visitor.visitSingularMessageField(value: v, fieldNumber: 149) }() case .loopContinue?: try { guard case .loopContinue(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 164) + try visitor.visitSingularMessageField(value: v, fieldNumber: 150) }() case .beginTry?: try { guard case .beginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 165) + try visitor.visitSingularMessageField(value: v, fieldNumber: 151) }() case .beginCatch?: try { guard case .beginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 166) + try visitor.visitSingularMessageField(value: v, fieldNumber: 152) }() case .beginFinally?: try { guard case .beginFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 167) + try visitor.visitSingularMessageField(value: v, fieldNumber: 153) }() case .endTryCatchFinally?: try { guard case .endTryCatchFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 168) + try visitor.visitSingularMessageField(value: v, fieldNumber: 154) }() case .throwException?: try { guard case .throwException(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 169) + try visitor.visitSingularMessageField(value: v, fieldNumber: 155) }() case .beginCodeString?: try { guard case .beginCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 170) + try visitor.visitSingularMessageField(value: v, fieldNumber: 156) }() case .endCodeString?: try { guard case .endCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 171) + try visitor.visitSingularMessageField(value: v, fieldNumber: 157) }() case .beginBlockStatement?: try { guard case .beginBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 172) + try visitor.visitSingularMessageField(value: v, fieldNumber: 158) }() case .endBlockStatement?: try { guard case .endBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 173) + try visitor.visitSingularMessageField(value: v, fieldNumber: 159) }() case .beginSwitch?: try { guard case .beginSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 174) + try visitor.visitSingularMessageField(value: v, fieldNumber: 160) }() case .beginSwitchCase?: try { guard case .beginSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 175) + try visitor.visitSingularMessageField(value: v, fieldNumber: 161) }() case .beginSwitchDefaultCase?: try { guard case .beginSwitchDefaultCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 176) + try visitor.visitSingularMessageField(value: v, fieldNumber: 162) }() case .endSwitchCase?: try { guard case .endSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 177) + try visitor.visitSingularMessageField(value: v, fieldNumber: 163) }() case .endSwitch?: try { guard case .endSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 178) + try visitor.visitSingularMessageField(value: v, fieldNumber: 164) }() case .switchBreak?: try { guard case .switchBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 179) + try visitor.visitSingularMessageField(value: v, fieldNumber: 165) }() case .loadNewTarget?: try { guard case .loadNewTarget(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 180) + try visitor.visitSingularMessageField(value: v, fieldNumber: 166) }() case .print?: try { guard case .print(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 181) + try visitor.visitSingularMessageField(value: v, fieldNumber: 167) }() case .explore?: try { guard case .explore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 182) + try visitor.visitSingularMessageField(value: v, fieldNumber: 168) }() case .probe?: try { guard case .probe(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 183) + try visitor.visitSingularMessageField(value: v, fieldNumber: 169) }() case .fixup?: try { guard case .fixup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 184) + try visitor.visitSingularMessageField(value: v, fieldNumber: 170) }() case .beginWasmModule?: try { guard case .beginWasmModule(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 185) + try visitor.visitSingularMessageField(value: v, fieldNumber: 171) }() case .endWasmModule?: try { guard case .endWasmModule(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 186) + try visitor.visitSingularMessageField(value: v, fieldNumber: 172) }() case .createWasmGlobal?: try { guard case .createWasmGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 187) + try visitor.visitSingularMessageField(value: v, fieldNumber: 173) }() case .createWasmMemory?: try { guard case .createWasmMemory(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 188) + try visitor.visitSingularMessageField(value: v, fieldNumber: 174) }() case .createWasmTable?: try { guard case .createWasmTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 189) + try visitor.visitSingularMessageField(value: v, fieldNumber: 175) }() case .createWasmJstag?: try { guard case .createWasmJstag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 190) + try visitor.visitSingularMessageField(value: v, fieldNumber: 176) }() case .createWasmTag?: try { guard case .createWasmTag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 191) + try visitor.visitSingularMessageField(value: v, fieldNumber: 177) }() case .wrapPromising?: try { guard case .wrapPromising(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 192) + try visitor.visitSingularMessageField(value: v, fieldNumber: 178) }() case .wrapSuspending?: try { guard case .wrapSuspending(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 193) + try visitor.visitSingularMessageField(value: v, fieldNumber: 179) }() case .bindMethod?: try { guard case .bindMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 194) + try visitor.visitSingularMessageField(value: v, fieldNumber: 180) }() case .bindFunction?: try { guard case .bindFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 195) + try visitor.visitSingularMessageField(value: v, fieldNumber: 181) }() case .consti64?: try { guard case .consti64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 196) + try visitor.visitSingularMessageField(value: v, fieldNumber: 182) }() case .consti32?: try { guard case .consti32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 197) + try visitor.visitSingularMessageField(value: v, fieldNumber: 183) }() case .constf32?: try { guard case .constf32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 198) + try visitor.visitSingularMessageField(value: v, fieldNumber: 184) }() case .constf64?: try { guard case .constf64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 199) + try visitor.visitSingularMessageField(value: v, fieldNumber: 185) }() case .wasmReturn?: try { guard case .wasmReturn(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 200) + try visitor.visitSingularMessageField(value: v, fieldNumber: 186) }() case .wasmJsCall?: try { guard case .wasmJsCall(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 201) + try visitor.visitSingularMessageField(value: v, fieldNumber: 187) }() case .wasmi32CompareOp?: try { guard case .wasmi32CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 202) + try visitor.visitSingularMessageField(value: v, fieldNumber: 188) }() case .wasmi64CompareOp?: try { guard case .wasmi64CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 203) + try visitor.visitSingularMessageField(value: v, fieldNumber: 189) }() case .wasmf32CompareOp?: try { guard case .wasmf32CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 204) + try visitor.visitSingularMessageField(value: v, fieldNumber: 190) }() case .wasmf64CompareOp?: try { guard case .wasmf64CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 205) + try visitor.visitSingularMessageField(value: v, fieldNumber: 191) }() case .wasmi32EqualZero?: try { guard case .wasmi32EqualZero(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 206) + try visitor.visitSingularMessageField(value: v, fieldNumber: 192) }() case .wasmi64EqualZero?: try { guard case .wasmi64EqualZero(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 207) + try visitor.visitSingularMessageField(value: v, fieldNumber: 193) }() case .wasmi32BinOp?: try { guard case .wasmi32BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 208) + try visitor.visitSingularMessageField(value: v, fieldNumber: 194) }() case .wasmi64BinOp?: try { guard case .wasmi64BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 209) + try visitor.visitSingularMessageField(value: v, fieldNumber: 195) }() case .wasmi32UnOp?: try { guard case .wasmi32UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 210) + try visitor.visitSingularMessageField(value: v, fieldNumber: 196) }() case .wasmi64UnOp?: try { guard case .wasmi64UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 211) + try visitor.visitSingularMessageField(value: v, fieldNumber: 197) }() case .wasmf32BinOp?: try { guard case .wasmf32BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 212) + try visitor.visitSingularMessageField(value: v, fieldNumber: 198) }() case .wasmf64BinOp?: try { guard case .wasmf64BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 213) + try visitor.visitSingularMessageField(value: v, fieldNumber: 199) }() case .wasmf32UnOp?: try { guard case .wasmf32UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 214) + try visitor.visitSingularMessageField(value: v, fieldNumber: 200) }() case .wasmf64UnOp?: try { guard case .wasmf64UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 215) + try visitor.visitSingularMessageField(value: v, fieldNumber: 201) }() case .wasmWrapi64Toi32?: try { guard case .wasmWrapi64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 216) + try visitor.visitSingularMessageField(value: v, fieldNumber: 202) }() case .wasmTruncatef32Toi32?: try { guard case .wasmTruncatef32Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 217) + try visitor.visitSingularMessageField(value: v, fieldNumber: 203) }() case .wasmTruncatef64Toi32?: try { guard case .wasmTruncatef64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 218) + try visitor.visitSingularMessageField(value: v, fieldNumber: 204) }() case .wasmExtendi32Toi64?: try { guard case .wasmExtendi32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 219) + try visitor.visitSingularMessageField(value: v, fieldNumber: 205) }() case .wasmTruncatef32Toi64?: try { guard case .wasmTruncatef32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 220) + try visitor.visitSingularMessageField(value: v, fieldNumber: 206) }() case .wasmTruncatef64Toi64?: try { guard case .wasmTruncatef64Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 221) + try visitor.visitSingularMessageField(value: v, fieldNumber: 207) }() case .wasmConverti32Tof32?: try { guard case .wasmConverti32Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 222) + try visitor.visitSingularMessageField(value: v, fieldNumber: 208) }() case .wasmConverti64Tof32?: try { guard case .wasmConverti64Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 223) + try visitor.visitSingularMessageField(value: v, fieldNumber: 209) }() case .wasmDemotef64Tof32?: try { guard case .wasmDemotef64Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 224) + try visitor.visitSingularMessageField(value: v, fieldNumber: 210) }() case .wasmConverti32Tof64?: try { guard case .wasmConverti32Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 225) + try visitor.visitSingularMessageField(value: v, fieldNumber: 211) }() case .wasmConverti64Tof64?: try { guard case .wasmConverti64Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 226) + try visitor.visitSingularMessageField(value: v, fieldNumber: 212) }() case .wasmPromotef32Tof64?: try { guard case .wasmPromotef32Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 227) + try visitor.visitSingularMessageField(value: v, fieldNumber: 213) }() case .wasmReinterpretf32Asi32?: try { guard case .wasmReinterpretf32Asi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 228) + try visitor.visitSingularMessageField(value: v, fieldNumber: 214) }() case .wasmReinterpretf64Asi64?: try { guard case .wasmReinterpretf64Asi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 229) + try visitor.visitSingularMessageField(value: v, fieldNumber: 215) }() case .wasmReinterpreti32Asf32?: try { guard case .wasmReinterpreti32Asf32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 230) + try visitor.visitSingularMessageField(value: v, fieldNumber: 216) }() case .wasmReinterpreti64Asf64?: try { guard case .wasmReinterpreti64Asf64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 231) + try visitor.visitSingularMessageField(value: v, fieldNumber: 217) }() case .wasmSignExtend8Intoi32?: try { guard case .wasmSignExtend8Intoi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 232) + try visitor.visitSingularMessageField(value: v, fieldNumber: 218) }() case .wasmSignExtend16Intoi32?: try { guard case .wasmSignExtend16Intoi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 233) + try visitor.visitSingularMessageField(value: v, fieldNumber: 219) }() case .wasmSignExtend8Intoi64?: try { guard case .wasmSignExtend8Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 234) + try visitor.visitSingularMessageField(value: v, fieldNumber: 220) }() case .wasmSignExtend16Intoi64?: try { guard case .wasmSignExtend16Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 235) + try visitor.visitSingularMessageField(value: v, fieldNumber: 221) }() case .wasmSignExtend32Intoi64?: try { guard case .wasmSignExtend32Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 236) + try visitor.visitSingularMessageField(value: v, fieldNumber: 222) }() case .wasmTruncateSatf32Toi32?: try { guard case .wasmTruncateSatf32Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 237) + try visitor.visitSingularMessageField(value: v, fieldNumber: 223) }() case .wasmTruncateSatf64Toi32?: try { guard case .wasmTruncateSatf64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 238) + try visitor.visitSingularMessageField(value: v, fieldNumber: 224) }() case .wasmTruncateSatf32Toi64?: try { guard case .wasmTruncateSatf32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 239) + try visitor.visitSingularMessageField(value: v, fieldNumber: 225) }() case .wasmTruncateSatf64Toi64?: try { guard case .wasmTruncateSatf64Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 240) + try visitor.visitSingularMessageField(value: v, fieldNumber: 226) }() case .wasmReassign?: try { guard case .wasmReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 241) + try visitor.visitSingularMessageField(value: v, fieldNumber: 227) }() case .wasmDefineGlobal?: try { guard case .wasmDefineGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 242) + try visitor.visitSingularMessageField(value: v, fieldNumber: 228) }() case .wasmDefineTable?: try { guard case .wasmDefineTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 243) + try visitor.visitSingularMessageField(value: v, fieldNumber: 229) }() case .wasmDefineMemory?: try { guard case .wasmDefineMemory(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 244) + try visitor.visitSingularMessageField(value: v, fieldNumber: 230) }() case .wasmDefineDataSegment?: try { guard case .wasmDefineDataSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 245) + try visitor.visitSingularMessageField(value: v, fieldNumber: 231) }() case .wasmLoadGlobal?: try { guard case .wasmLoadGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 246) + try visitor.visitSingularMessageField(value: v, fieldNumber: 232) }() case .wasmStoreGlobal?: try { guard case .wasmStoreGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 247) + try visitor.visitSingularMessageField(value: v, fieldNumber: 233) }() case .wasmTableGet?: try { guard case .wasmTableGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 248) + try visitor.visitSingularMessageField(value: v, fieldNumber: 234) }() case .wasmTableSet?: try { guard case .wasmTableSet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 249) + try visitor.visitSingularMessageField(value: v, fieldNumber: 235) }() case .wasmTableSize?: try { guard case .wasmTableSize(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 250) + try visitor.visitSingularMessageField(value: v, fieldNumber: 236) }() case .wasmTableGrow?: try { guard case .wasmTableGrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 251) + try visitor.visitSingularMessageField(value: v, fieldNumber: 237) }() case .wasmCallIndirect?: try { guard case .wasmCallIndirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 252) + try visitor.visitSingularMessageField(value: v, fieldNumber: 238) }() case .wasmCallDirect?: try { guard case .wasmCallDirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 253) + try visitor.visitSingularMessageField(value: v, fieldNumber: 239) }() case .wasmReturnCallDirect?: try { guard case .wasmReturnCallDirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 254) + try visitor.visitSingularMessageField(value: v, fieldNumber: 240) }() case .wasmReturnCallIndirect?: try { guard case .wasmReturnCallIndirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 255) + try visitor.visitSingularMessageField(value: v, fieldNumber: 241) }() case .wasmMemoryLoad?: try { guard case .wasmMemoryLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 256) + try visitor.visitSingularMessageField(value: v, fieldNumber: 242) }() case .wasmMemoryStore?: try { guard case .wasmMemoryStore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 257) + try visitor.visitSingularMessageField(value: v, fieldNumber: 243) }() case .wasmAtomicLoad?: try { guard case .wasmAtomicLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 258) + try visitor.visitSingularMessageField(value: v, fieldNumber: 244) }() case .wasmAtomicStore?: try { guard case .wasmAtomicStore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 259) + try visitor.visitSingularMessageField(value: v, fieldNumber: 245) }() case .wasmAtomicRmw?: try { guard case .wasmAtomicRmw(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 260) + try visitor.visitSingularMessageField(value: v, fieldNumber: 246) }() case .wasmAtomicCmpxchg?: try { guard case .wasmAtomicCmpxchg(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 261) + try visitor.visitSingularMessageField(value: v, fieldNumber: 247) }() case .wasmMemorySize?: try { guard case .wasmMemorySize(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 262) + try visitor.visitSingularMessageField(value: v, fieldNumber: 248) }() case .wasmMemoryGrow?: try { guard case .wasmMemoryGrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 263) + try visitor.visitSingularMessageField(value: v, fieldNumber: 249) }() case .wasmMemoryFill?: try { guard case .wasmMemoryFill(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 264) + try visitor.visitSingularMessageField(value: v, fieldNumber: 250) }() case .wasmMemoryInit?: try { guard case .wasmMemoryInit(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 265) + try visitor.visitSingularMessageField(value: v, fieldNumber: 251) }() case .wasmDropDataSegment?: try { guard case .wasmDropDataSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 266) + try visitor.visitSingularMessageField(value: v, fieldNumber: 252) }() case .beginWasmFunction?: try { guard case .beginWasmFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 267) + try visitor.visitSingularMessageField(value: v, fieldNumber: 253) }() case .endWasmFunction?: try { guard case .endWasmFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 268) + try visitor.visitSingularMessageField(value: v, fieldNumber: 254) }() case .wasmBeginBlock?: try { guard case .wasmBeginBlock(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 269) + try visitor.visitSingularMessageField(value: v, fieldNumber: 255) }() case .wasmEndBlock?: try { guard case .wasmEndBlock(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 270) + try visitor.visitSingularMessageField(value: v, fieldNumber: 256) }() case .wasmBeginLoop?: try { guard case .wasmBeginLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 271) + try visitor.visitSingularMessageField(value: v, fieldNumber: 257) }() case .wasmEndLoop?: try { guard case .wasmEndLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 272) + try visitor.visitSingularMessageField(value: v, fieldNumber: 258) }() case .wasmBranch?: try { guard case .wasmBranch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 273) + try visitor.visitSingularMessageField(value: v, fieldNumber: 259) }() case .wasmBranchIf?: try { guard case .wasmBranchIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 274) + try visitor.visitSingularMessageField(value: v, fieldNumber: 260) }() case .wasmBranchTable?: try { guard case .wasmBranchTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 275) + try visitor.visitSingularMessageField(value: v, fieldNumber: 261) }() case .wasmNop?: try { guard case .wasmNop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 276) + try visitor.visitSingularMessageField(value: v, fieldNumber: 262) }() case .wasmBeginIf?: try { guard case .wasmBeginIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 277) + try visitor.visitSingularMessageField(value: v, fieldNumber: 263) }() case .wasmBeginElse?: try { guard case .wasmBeginElse(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 278) + try visitor.visitSingularMessageField(value: v, fieldNumber: 264) }() case .wasmEndIf?: try { guard case .wasmEndIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 279) + try visitor.visitSingularMessageField(value: v, fieldNumber: 265) }() case .wasmBeginTryTable?: try { guard case .wasmBeginTryTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 280) + try visitor.visitSingularMessageField(value: v, fieldNumber: 266) }() case .wasmEndTryTable?: try { guard case .wasmEndTryTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 281) + try visitor.visitSingularMessageField(value: v, fieldNumber: 267) }() case .wasmBeginTry?: try { guard case .wasmBeginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 282) + try visitor.visitSingularMessageField(value: v, fieldNumber: 268) }() case .wasmBeginCatchAll?: try { guard case .wasmBeginCatchAll(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 283) + try visitor.visitSingularMessageField(value: v, fieldNumber: 269) }() case .wasmBeginCatch?: try { guard case .wasmBeginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 284) + try visitor.visitSingularMessageField(value: v, fieldNumber: 270) }() case .wasmEndTry?: try { guard case .wasmEndTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 285) + try visitor.visitSingularMessageField(value: v, fieldNumber: 271) }() case .wasmBeginTryDelegate?: try { guard case .wasmBeginTryDelegate(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 286) + try visitor.visitSingularMessageField(value: v, fieldNumber: 272) }() case .wasmEndTryDelegate?: try { guard case .wasmEndTryDelegate(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 287) + try visitor.visitSingularMessageField(value: v, fieldNumber: 273) }() case .wasmThrow?: try { guard case .wasmThrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 288) + try visitor.visitSingularMessageField(value: v, fieldNumber: 274) }() case .wasmRethrow?: try { guard case .wasmRethrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 289) + try visitor.visitSingularMessageField(value: v, fieldNumber: 275) }() case .wasmThrowRef?: try { guard case .wasmThrowRef(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 290) + try visitor.visitSingularMessageField(value: v, fieldNumber: 276) }() case .wasmDefineTag?: try { guard case .wasmDefineTag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 291) + try visitor.visitSingularMessageField(value: v, fieldNumber: 277) }() case .constSimd128?: try { guard case .constSimd128(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 292) + try visitor.visitSingularMessageField(value: v, fieldNumber: 278) }() case .wasmSimd128Compare?: try { guard case .wasmSimd128Compare(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 293) + try visitor.visitSingularMessageField(value: v, fieldNumber: 279) }() case .wasmSimd128IntegerUnOp?: try { guard case .wasmSimd128IntegerUnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 294) + try visitor.visitSingularMessageField(value: v, fieldNumber: 280) }() case .wasmSimd128IntegerBinOp?: try { guard case .wasmSimd128IntegerBinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 295) + try visitor.visitSingularMessageField(value: v, fieldNumber: 281) }() case .wasmSimd128IntegerTernaryOp?: try { guard case .wasmSimd128IntegerTernaryOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 296) + try visitor.visitSingularMessageField(value: v, fieldNumber: 282) }() case .wasmSimd128FloatUnOp?: try { guard case .wasmSimd128FloatUnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 297) + try visitor.visitSingularMessageField(value: v, fieldNumber: 283) }() case .wasmSimd128FloatBinOp?: try { guard case .wasmSimd128FloatBinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 298) + try visitor.visitSingularMessageField(value: v, fieldNumber: 284) }() case .wasmSimd128FloatTernaryOp?: try { guard case .wasmSimd128FloatTernaryOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 299) + try visitor.visitSingularMessageField(value: v, fieldNumber: 285) }() case .wasmSimdSplat?: try { guard case .wasmSimdSplat(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 300) + try visitor.visitSingularMessageField(value: v, fieldNumber: 286) }() case .wasmSimdExtractLane?: try { guard case .wasmSimdExtractLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 301) + try visitor.visitSingularMessageField(value: v, fieldNumber: 287) }() case .wasmSimdReplaceLane?: try { guard case .wasmSimdReplaceLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 302) + try visitor.visitSingularMessageField(value: v, fieldNumber: 288) }() case .wasmSimdStoreLane?: try { guard case .wasmSimdStoreLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 303) + try visitor.visitSingularMessageField(value: v, fieldNumber: 289) }() case .wasmSimdLoadLane?: try { guard case .wasmSimdLoadLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 304) + try visitor.visitSingularMessageField(value: v, fieldNumber: 290) }() case .wasmSimdLoad?: try { guard case .wasmSimdLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 305) + try visitor.visitSingularMessageField(value: v, fieldNumber: 291) }() case .wasmUnreachable?: try { guard case .wasmUnreachable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 306) + try visitor.visitSingularMessageField(value: v, fieldNumber: 292) }() case .wasmSelect?: try { guard case .wasmSelect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 307) + try visitor.visitSingularMessageField(value: v, fieldNumber: 293) }() case .wasmBeginTypeGroup?: try { guard case .wasmBeginTypeGroup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 308) + try visitor.visitSingularMessageField(value: v, fieldNumber: 294) }() case .wasmEndTypeGroup?: try { guard case .wasmEndTypeGroup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 309) + try visitor.visitSingularMessageField(value: v, fieldNumber: 295) }() case .wasmDefineArrayType?: try { guard case .wasmDefineArrayType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 310) + try visitor.visitSingularMessageField(value: v, fieldNumber: 296) }() case .wasmDefineStructType?: try { guard case .wasmDefineStructType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 311) + try visitor.visitSingularMessageField(value: v, fieldNumber: 297) }() case .wasmDefineForwardOrSelfReference?: try { guard case .wasmDefineForwardOrSelfReference(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 312) + try visitor.visitSingularMessageField(value: v, fieldNumber: 298) }() case .wasmResolveForwardReference?: try { guard case .wasmResolveForwardReference(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 313) + try visitor.visitSingularMessageField(value: v, fieldNumber: 299) }() case .wasmArrayNewFixed?: try { guard case .wasmArrayNewFixed(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 314) + try visitor.visitSingularMessageField(value: v, fieldNumber: 300) }() case .wasmArrayNewDefault?: try { guard case .wasmArrayNewDefault(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 315) + try visitor.visitSingularMessageField(value: v, fieldNumber: 301) }() case .wasmArrayLen?: try { guard case .wasmArrayLen(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 316) + try visitor.visitSingularMessageField(value: v, fieldNumber: 302) }() case .wasmArrayGet?: try { guard case .wasmArrayGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 317) + try visitor.visitSingularMessageField(value: v, fieldNumber: 303) }() case .wasmArraySet?: try { guard case .wasmArraySet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 318) + try visitor.visitSingularMessageField(value: v, fieldNumber: 304) }() case .wasmStructNewDefault?: try { guard case .wasmStructNewDefault(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 319) + try visitor.visitSingularMessageField(value: v, fieldNumber: 305) }() case .wasmStructGet?: try { guard case .wasmStructGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 320) + try visitor.visitSingularMessageField(value: v, fieldNumber: 306) }() case .wasmStructSet?: try { guard case .wasmStructSet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 321) + try visitor.visitSingularMessageField(value: v, fieldNumber: 307) }() case .wasmRefNull?: try { guard case .wasmRefNull(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 322) + try visitor.visitSingularMessageField(value: v, fieldNumber: 308) }() case .wasmRefIsNull?: try { guard case .wasmRefIsNull(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 323) + try visitor.visitSingularMessageField(value: v, fieldNumber: 309) }() case .wasmRefI31?: try { guard case .wasmRefI31(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 324) + try visitor.visitSingularMessageField(value: v, fieldNumber: 310) }() case .wasmI31Get?: try { guard case .wasmI31Get(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 325) + try visitor.visitSingularMessageField(value: v, fieldNumber: 311) }() case .wasmAnyConvertExtern?: try { guard case .wasmAnyConvertExtern(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 326) + try visitor.visitSingularMessageField(value: v, fieldNumber: 312) }() case .wasmExternConvertAny?: try { guard case .wasmExternConvertAny(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 327) + try visitor.visitSingularMessageField(value: v, fieldNumber: 313) }() case .wasmMemoryCopy?: try { guard case .wasmMemoryCopy(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 328) + try visitor.visitSingularMessageField(value: v, fieldNumber: 314) }() case .wasmDefineElementSegment?: try { guard case .wasmDefineElementSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 329) + try visitor.visitSingularMessageField(value: v, fieldNumber: 315) }() case .wasmTableInit?: try { guard case .wasmTableInit(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 330) + try visitor.visitSingularMessageField(value: v, fieldNumber: 316) }() case .wasmDropElementSegment?: try { guard case .wasmDropElementSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 331) + try visitor.visitSingularMessageField(value: v, fieldNumber: 317) }() case .wasmTableCopy?: try { guard case .wasmTableCopy(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 332) + try visitor.visitSingularMessageField(value: v, fieldNumber: 318) }() case .wasmDefineSignatureType?: try { guard case .wasmDefineSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 333) + try visitor.visitSingularMessageField(value: v, fieldNumber: 319) }() case .createNamedDisposableVariable?: try { guard case .createNamedDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 334) + try visitor.visitSingularMessageField(value: v, fieldNumber: 320) }() case .createNamedAsyncDisposableVariable?: try { guard case .createNamedAsyncDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 335) + try visitor.visitSingularMessageField(value: v, fieldNumber: 321) }() case .wasmDefineAdHocSignatureType?: try { guard case .wasmDefineAdHocSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 336) + try visitor.visitSingularMessageField(value: v, fieldNumber: 322) }() case .wasmStructNew?: try { guard case .wasmStructNew(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 337) + try visitor.visitSingularMessageField(value: v, fieldNumber: 323) }() case .wasmRefEq?: try { guard case .wasmRefEq(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 338) + try visitor.visitSingularMessageField(value: v, fieldNumber: 324) }() case .wasmRefTest?: try { guard case .wasmRefTest(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 339) + try visitor.visitSingularMessageField(value: v, fieldNumber: 325) }() case .wasmDefineAdHocModuleSignatureType?: try { guard case .wasmDefineAdHocModuleSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 340) + try visitor.visitSingularMessageField(value: v, fieldNumber: 326) }() case .wasmRefCast?: try { guard case .wasmRefCast(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 341) + try visitor.visitSingularMessageField(value: v, fieldNumber: 327) }() case nil: break } diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 1ae505cf7..abf2a678c 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -58,313 +58,299 @@ message Instruction { BeginClassDefinition beginClassDefinition = 32; BeginClassConstructor beginClassConstructor = 33; EndClassConstructor endClassConstructor = 34; - ClassAddInstanceProperty classAddInstanceProperty = 35; - ClassAddInstanceElement classAddInstanceElement = 36; - ClassAddInstanceComputedProperty classAddInstanceComputedProperty = 37; - BeginClassInstanceMethod beginClassInstanceMethod = 38; - EndClassInstanceMethod endClassInstanceMethod = 39; - BeginClassInstanceComputedMethod beginClassInstanceComputedMethod = 40; - EndClassInstanceComputedMethod endClassInstanceComputedMethod = 41; - BeginClassInstanceGetter beginClassInstanceGetter = 42; - EndClassInstanceGetter endClassInstanceGetter = 43; - BeginClassInstanceSetter beginClassInstanceSetter = 44; - EndClassInstanceSetter endClassInstanceSetter = 45; - ClassAddStaticProperty classAddStaticProperty = 46; - ClassAddStaticElement classAddStaticElement = 47; - ClassAddStaticComputedProperty classAddStaticComputedProperty = 48; - BeginClassStaticInitializer beginClassStaticInitializer = 49; - EndClassStaticInitializer endClassStaticInitializer = 50; - BeginClassStaticMethod beginClassStaticMethod = 51; - EndClassStaticMethod endClassStaticMethod = 52; - BeginClassStaticComputedMethod beginClassStaticComputedMethod = 53; - EndClassStaticComputedMethod endClassStaticComputedMethod = 54; - BeginClassStaticGetter beginClassStaticGetter = 55; - EndClassStaticGetter endClassStaticGetter = 56; - BeginClassStaticSetter beginClassStaticSetter = 57; - EndClassStaticSetter endClassStaticSetter = 58; - ClassAddPrivateInstanceProperty classAddPrivateInstanceProperty = 59; - BeginClassPrivateInstanceMethod beginClassPrivateInstanceMethod = 60; - EndClassPrivateInstanceMethod endClassPrivateInstanceMethod = 61; - ClassAddPrivateStaticProperty classAddPrivateStaticProperty = 62; - BeginClassPrivateStaticMethod beginClassPrivateStaticMethod = 63; - EndClassPrivateStaticMethod endClassPrivateStaticMethod = 64; - EndClassDefinition endClassDefinition = 65; - CreateArray createArray = 66; - CreateIntArray createIntArray = 67; - CreateFloatArray createFloatArray = 68; - CreateArrayWithSpread createArrayWithSpread = 69; - CreateTemplateString createTemplateString = 70; - GetProperty getProperty = 71; - SetProperty setProperty = 72; - UpdateProperty updateProperty = 73; - DeleteProperty deleteProperty = 74; - ConfigureProperty configureProperty = 75; - GetElement getElement = 76; - SetElement setElement = 77; - UpdateElement updateElement = 78; - DeleteElement deleteElement = 79; - ConfigureElement configureElement = 80; - GetComputedProperty getComputedProperty = 81; - SetComputedProperty setComputedProperty = 82; - UpdateComputedProperty updateComputedProperty = 83; - DeleteComputedProperty deleteComputedProperty = 84; - ConfigureComputedProperty configureComputedProperty = 85; - TypeOf typeOf = 86; - Void void = 87; - TestInstanceOf testInstanceOf = 88; - TestIn testIn = 89; - BeginPlainFunction beginPlainFunction = 90; - EndPlainFunction endPlainFunction = 91; - BeginArrowFunction beginArrowFunction = 92; - EndArrowFunction endArrowFunction = 93; - BeginGeneratorFunction beginGeneratorFunction = 94; - EndGeneratorFunction endGeneratorFunction = 95; - BeginAsyncFunction beginAsyncFunction = 96; - EndAsyncFunction endAsyncFunction = 97; - BeginAsyncArrowFunction beginAsyncArrowFunction = 98; - EndAsyncArrowFunction endAsyncArrowFunction = 99; - BeginAsyncGeneratorFunction beginAsyncGeneratorFunction = 100; - EndAsyncGeneratorFunction endAsyncGeneratorFunction = 101; - BeginConstructor beginConstructor = 102; - EndConstructor endConstructor = 103; - Directive directive = 104; - Return return = 105; - Yield yield = 106; - YieldEach yieldEach = 107; - Await await = 108; - CallFunction callFunction = 109; - CallFunctionWithSpread callFunctionWithSpread = 110; - Construct construct = 111; - ConstructWithSpread constructWithSpread = 112; - CallMethod callMethod = 113; - CallMethodWithSpread callMethodWithSpread = 114; - CallComputedMethod callComputedMethod = 115; - CallComputedMethodWithSpread callComputedMethodWithSpread = 116; - UnaryOperation unaryOperation = 117; - BinaryOperation binaryOperation = 118; - TernaryOperation ternaryOperation = 119; - Update update = 120; - Dup dup = 121; - Reassign reassign = 122; - DestructArray destructArray = 123; - DestructArrayAndReassign destructArrayAndReassign = 124; - DestructObject destructObject = 125; - DestructObjectAndReassign destructObjectAndReassign = 126; - Compare compare = 127; - Eval eval = 128; - BeginWith beginWith = 129; - EndWith endWith = 130; - CallSuperConstructor callSuperConstructor = 131; - CallSuperMethod callSuperMethod = 132; - GetPrivateProperty getPrivateProperty = 133; - SetPrivateProperty setPrivateProperty = 134; - UpdatePrivateProperty updatePrivateProperty = 135; - CallPrivateMethod callPrivateMethod = 136; - GetSuperProperty getSuperProperty = 137; - SetSuperProperty setSuperProperty = 138; - GetComputedSuperProperty getComputedSuperProperty = 139; - SetComputedSuperProperty setComputedSuperProperty = 140; - UpdateSuperProperty updateSuperProperty = 141; - BeginIf beginIf = 142; - BeginElse beginElse = 143; - EndIf endIf = 144; - BeginWhileLoopHeader beginWhileLoopHeader = 145; - BeginWhileLoopBody beginWhileLoopBody = 146; - EndWhileLoop endWhileLoop = 147; - BeginDoWhileLoopBody beginDoWhileLoopBody = 148; - BeginDoWhileLoopHeader beginDoWhileLoopHeader = 149; - EndDoWhileLoop endDoWhileLoop = 150; - BeginForLoopInitializer beginForLoopInitializer = 151; - BeginForLoopCondition beginForLoopCondition = 152; - BeginForLoopAfterthought beginForLoopAfterthought = 153; - BeginForLoopBody beginForLoopBody = 154; - EndForLoop endForLoop = 155; - BeginForInLoop beginForInLoop = 156; - EndForInLoop endForInLoop = 157; - BeginForOfLoop beginForOfLoop = 158; - BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 159; - EndForOfLoop endForOfLoop = 160; - BeginRepeatLoop beginRepeatLoop = 161; - EndRepeatLoop endRepeatLoop = 162; - LoopBreak loopBreak = 163; - LoopContinue loopContinue = 164; - BeginTry beginTry = 165; - BeginCatch beginCatch = 166; - BeginFinally beginFinally = 167; - EndTryCatchFinally endTryCatchFinally = 168; - ThrowException throwException = 169; - BeginCodeString beginCodeString = 170; - EndCodeString endCodeString = 171; - BeginBlockStatement beginBlockStatement = 172; - EndBlockStatement endBlockStatement = 173; - BeginSwitch beginSwitch = 174; - BeginSwitchCase beginSwitchCase = 175; - BeginSwitchDefaultCase beginSwitchDefaultCase = 176; - EndSwitchCase endSwitchCase = 177; - EndSwitch endSwitch = 178; - SwitchBreak switchBreak = 179; - LoadNewTarget loadNewTarget = 180; - Print print = 181; - Explore explore = 182; - Probe probe = 183; - Fixup fixup = 184; - BeginWasmModule beginWasmModule = 185; - EndWasmModule endWasmModule = 186; - CreateWasmGlobal createWasmGlobal = 187; - CreateWasmMemory createWasmMemory = 188; - CreateWasmTable createWasmTable = 189; - CreateWasmJSTag createWasmJSTag = 190; - CreateWasmTag createWasmTag = 191; - WrapPromising wrapPromising = 192; - WrapSuspending wrapSuspending = 193; - BindMethod bindMethod = 194; - BindFunction bindFunction = 195; - Consti64 consti64 = 196; - Consti32 consti32 = 197; - Constf32 constf32 = 198; - Constf64 constf64 = 199; - WasmReturn wasmReturn = 200; - WasmJsCall wasmJsCall = 201; - Wasmi32CompareOp wasmi32CompareOp = 202; - Wasmi64CompareOp wasmi64CompareOp = 203; - Wasmf32CompareOp wasmf32CompareOp = 204; - Wasmf64CompareOp wasmf64CompareOp = 205; - Wasmi32EqualZero wasmi32EqualZero = 206; - Wasmi64EqualZero wasmi64EqualZero = 207; - Wasmi32BinOp wasmi32BinOp = 208; - Wasmi64BinOp wasmi64BinOp = 209; - Wasmi32UnOp wasmi32UnOp = 210; - Wasmi64UnOp wasmi64UnOp = 211; - Wasmf32BinOp wasmf32BinOp = 212; - Wasmf64BinOp wasmf64BinOp = 213; - Wasmf32UnOp wasmf32UnOp = 214; - Wasmf64UnOp wasmf64UnOp = 215; - WasmWrapi64Toi32 wasmWrapi64Toi32 = 216; - WasmTruncatef32Toi32 wasmTruncatef32Toi32 = 217; - WasmTruncatef64Toi32 wasmTruncatef64Toi32 = 218; - WasmExtendi32Toi64 wasmExtendi32Toi64 = 219; - WasmTruncatef32Toi64 wasmTruncatef32Toi64 = 220; - WasmTruncatef64Toi64 wasmTruncatef64Toi64 = 221; - WasmConverti32Tof32 wasmConverti32Tof32 = 222; - WasmConverti64Tof32 wasmConverti64Tof32 = 223; - WasmDemotef64Tof32 wasmDemotef64Tof32 = 224; - WasmConverti32Tof64 wasmConverti32Tof64 = 225; - WasmConverti64Tof64 wasmConverti64Tof64 = 226; - WasmPromotef32Tof64 wasmPromotef32Tof64 = 227; - WasmReinterpretf32Asi32 wasmReinterpretf32Asi32 = 228; - WasmReinterpretf64Asi64 wasmReinterpretf64Asi64 = 229; - WasmReinterpreti32Asf32 wasmReinterpreti32Asf32 = 230; - WasmReinterpreti64Asf64 wasmReinterpreti64Asf64 = 231; - WasmSignExtend8Intoi32 wasmSignExtend8Intoi32 = 232; - WasmSignExtend16Intoi32 wasmSignExtend16Intoi32 = 233; - WasmSignExtend8Intoi64 wasmSignExtend8Intoi64 = 234; - WasmSignExtend16Intoi64 wasmSignExtend16Intoi64 = 235; - WasmSignExtend32Intoi64 wasmSignExtend32Intoi64 = 236; - WasmTruncateSatf32Toi32 wasmTruncateSatf32Toi32 = 237; - WasmTruncateSatf64Toi32 wasmTruncateSatf64Toi32 = 238; - WasmTruncateSatf32Toi64 wasmTruncateSatf32Toi64 = 239; - WasmTruncateSatf64Toi64 wasmTruncateSatf64Toi64 = 240; - WasmReassign wasmReassign = 241; - WasmDefineGlobal wasmDefineGlobal = 242; - WasmDefineTable wasmDefineTable = 243; - WasmDefineMemory wasmDefineMemory = 244; - WasmDefineDataSegment wasmDefineDataSegment = 245; - WasmLoadGlobal wasmLoadGlobal = 246; - WasmStoreGlobal wasmStoreGlobal = 247; - WasmTableGet wasmTableGet = 248; - WasmTableSet wasmTableSet = 249; - WasmTableSize wasmTableSize = 250; - WasmTableGrow wasmTableGrow = 251; - WasmCallIndirect wasmCallIndirect = 252; - WasmCallDirect wasmCallDirect = 253; - WasmReturnCallDirect wasmReturnCallDirect = 254; - WasmReturnCallIndirect wasmReturnCallIndirect = 255; - WasmMemoryLoad wasmMemoryLoad = 256; - WasmMemoryStore wasmMemoryStore = 257; - WasmAtomicLoad wasmAtomicLoad = 258; - WasmAtomicStore wasmAtomicStore = 259; - WasmAtomicRMW wasmAtomicRMW = 260; - WasmAtomicCmpxchg wasmAtomicCmpxchg = 261; - WasmMemorySize wasmMemorySize = 262; - WasmMemoryGrow wasmMemoryGrow = 263; - WasmMemoryFill wasmMemoryFill = 264; - WasmMemoryInit wasmMemoryInit = 265; - WasmDropDataSegment wasmDropDataSegment = 266; - BeginWasmFunction beginWasmFunction = 267; - EndWasmFunction endWasmFunction = 268; - WasmBeginBlock wasmBeginBlock = 269; - WasmEndBlock wasmEndBlock = 270; - WasmBeginLoop wasmBeginLoop = 271; - WasmEndLoop wasmEndLoop = 272; - WasmBranch wasmBranch = 273; - WasmBranchIf wasmBranchIf = 274; - WasmBranchTable wasmBranchTable = 275; - WasmNop wasmNop = 276; - WasmBeginIf wasmBeginIf = 277; - WasmBeginElse wasmBeginElse = 278; - WasmEndIf wasmEndIf = 279; - WasmBeginTryTable wasmBeginTryTable = 280; - WasmEndTryTable wasmEndTryTable = 281; - WasmBeginTry wasmBeginTry = 282; - WasmBeginCatchAll wasmBeginCatchAll = 283; - WasmBeginCatch wasmBeginCatch = 284; - WasmEndTry wasmEndTry = 285; - WasmBeginTryDelegate wasmBeginTryDelegate = 286; - WasmEndTryDelegate wasmEndTryDelegate = 287; - WasmThrow wasmThrow = 288; - WasmRethrow wasmRethrow = 289; - WasmThrowRef wasmThrowRef = 290; - WasmDefineTag wasmDefineTag = 291; - ConstSimd128 constSimd128 = 292; - WasmSimd128Compare wasmSimd128Compare = 293; - WasmSimd128IntegerUnOp wasmSimd128IntegerUnOp = 294; - WasmSimd128IntegerBinOp wasmSimd128IntegerBinOp = 295; - WasmSimd128IntegerTernaryOp wasmSimd128IntegerTernaryOp = 296; - WasmSimd128FloatUnOp wasmSimd128FloatUnOp = 297; - WasmSimd128FloatBinOp wasmSimd128FloatBinOp = 298; - WasmSimd128FloatTernaryOp wasmSimd128FloatTernaryOp = 299; - WasmSimdSplat wasmSimdSplat = 300; - WasmSimdExtractLane wasmSimdExtractLane = 301; - WasmSimdReplaceLane wasmSimdReplaceLane = 302; - WasmSimdStoreLane wasmSimdStoreLane = 303; - WasmSimdLoadLane wasmSimdLoadLane = 304; - WasmSimdLoad wasmSimdLoad = 305; - WasmUnreachable wasmUnreachable = 306; - WasmSelect wasmSelect = 307; - WasmBeginTypeGroup wasmBeginTypeGroup = 308; - WasmEndTypeGroup wasmEndTypeGroup = 309; - WasmDefineArrayType wasmDefineArrayType = 310; - WasmDefineStructType wasmDefineStructType = 311; - WasmDefineForwardOrSelfReference wasmDefineForwardOrSelfReference = 312; - WasmResolveForwardReference wasmResolveForwardReference = 313; - WasmArrayNewFixed wasmArrayNewFixed = 314; - WasmArrayNewDefault wasmArrayNewDefault = 315; - WasmArrayLen wasmArrayLen = 316; - WasmArrayGet wasmArrayGet = 317; - WasmArraySet wasmArraySet = 318; - WasmStructNewDefault wasmStructNewDefault = 319; - WasmStructGet wasmStructGet = 320; - WasmStructSet wasmStructSet = 321; - WasmRefNull wasmRefNull = 322; - WasmRefIsNull wasmRefIsNull = 323; - WasmRefI31 wasmRefI31 = 324; - WasmI31Get wasmI31Get = 325; - WasmAnyConvertExtern wasmAnyConvertExtern = 326; - WasmExternConvertAny wasmExternConvertAny = 327; - WasmMemoryCopy wasmMemoryCopy = 328; - WasmDefineElementSegment wasmDefineElementSegment = 329; - WasmTableInit wasmTableInit = 330; - WasmDropElementSegment wasmDropElementSegment = 331; - WasmTableCopy wasmTableCopy = 332; - WasmDefineSignatureType wasmDefineSignatureType = 333; - CreateNamedDisposableVariable createNamedDisposableVariable = 334; - CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 335; - WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; - WasmStructNew wasmStructNew = 337; - WasmRefEq wasmRefEq = 338; - WasmRefTest wasmRefTest = 339; - WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 340; - WasmRefCast wasmRefCast = 341; + ClassAddProperty classAddProperty = 35; + ClassAddElement classAddElement = 36; + ClassAddComputedProperty classAddComputedProperty = 37; + BeginClassMethod beginClassMethod = 38; + EndClassMethod endClassMethod = 39; + BeginClassComputedMethod beginClassComputedMethod = 40; + EndClassComputedMethod endClassComputedMethod = 41; + BeginClassGetter beginClassGetter = 42; + EndClassGetter endClassGetter = 43; + BeginClassSetter beginClassSetter = 44; + EndClassSetter endClassSetter = 45; + BeginClassStaticInitializer beginClassStaticInitializer = 46; + EndClassStaticInitializer endClassStaticInitializer = 47; + ClassAddPrivateProperty classAddPrivateProperty = 48; + BeginClassPrivateMethod beginClassPrivateMethod = 49; + EndClassPrivateMethod endClassPrivateMethod = 50; + EndClassDefinition endClassDefinition = 51; + CreateArray createArray = 52; + CreateIntArray createIntArray = 53; + CreateFloatArray createFloatArray = 54; + CreateArrayWithSpread createArrayWithSpread = 55; + CreateTemplateString createTemplateString = 56; + GetProperty getProperty = 57; + SetProperty setProperty = 58; + UpdateProperty updateProperty = 59; + DeleteProperty deleteProperty = 60; + ConfigureProperty configureProperty = 61; + GetElement getElement = 62; + SetElement setElement = 63; + UpdateElement updateElement = 64; + DeleteElement deleteElement = 65; + ConfigureElement configureElement = 66; + GetComputedProperty getComputedProperty = 67; + SetComputedProperty setComputedProperty = 68; + UpdateComputedProperty updateComputedProperty = 69; + DeleteComputedProperty deleteComputedProperty = 70; + ConfigureComputedProperty configureComputedProperty = 71; + TypeOf typeOf = 72; + Void void = 73; + TestInstanceOf testInstanceOf = 74; + TestIn testIn = 75; + BeginPlainFunction beginPlainFunction = 76; + EndPlainFunction endPlainFunction = 77; + BeginArrowFunction beginArrowFunction = 78; + EndArrowFunction endArrowFunction = 79; + BeginGeneratorFunction beginGeneratorFunction = 80; + EndGeneratorFunction endGeneratorFunction = 81; + BeginAsyncFunction beginAsyncFunction = 82; + EndAsyncFunction endAsyncFunction = 83; + BeginAsyncArrowFunction beginAsyncArrowFunction = 84; + EndAsyncArrowFunction endAsyncArrowFunction = 85; + BeginAsyncGeneratorFunction beginAsyncGeneratorFunction = 86; + EndAsyncGeneratorFunction endAsyncGeneratorFunction = 87; + BeginConstructor beginConstructor = 88; + EndConstructor endConstructor = 89; + Directive directive = 90; + Return return = 91; + Yield yield = 92; + YieldEach yieldEach = 93; + Await await = 94; + CallFunction callFunction = 95; + CallFunctionWithSpread callFunctionWithSpread = 96; + Construct construct = 97; + ConstructWithSpread constructWithSpread = 98; + CallMethod callMethod = 99; + CallMethodWithSpread callMethodWithSpread = 100; + CallComputedMethod callComputedMethod = 101; + CallComputedMethodWithSpread callComputedMethodWithSpread = 102; + UnaryOperation unaryOperation = 103; + BinaryOperation binaryOperation = 104; + TernaryOperation ternaryOperation = 105; + Update update = 106; + Dup dup = 107; + Reassign reassign = 108; + DestructArray destructArray = 109; + DestructArrayAndReassign destructArrayAndReassign = 110; + DestructObject destructObject = 111; + DestructObjectAndReassign destructObjectAndReassign = 112; + Compare compare = 113; + Eval eval = 114; + BeginWith beginWith = 115; + EndWith endWith = 116; + CallSuperConstructor callSuperConstructor = 117; + CallSuperMethod callSuperMethod = 118; + GetPrivateProperty getPrivateProperty = 119; + SetPrivateProperty setPrivateProperty = 120; + UpdatePrivateProperty updatePrivateProperty = 121; + CallPrivateMethod callPrivateMethod = 122; + GetSuperProperty getSuperProperty = 123; + SetSuperProperty setSuperProperty = 124; + GetComputedSuperProperty getComputedSuperProperty = 125; + SetComputedSuperProperty setComputedSuperProperty = 126; + UpdateSuperProperty updateSuperProperty = 127; + BeginIf beginIf = 128; + BeginElse beginElse = 129; + EndIf endIf = 130; + BeginWhileLoopHeader beginWhileLoopHeader = 131; + BeginWhileLoopBody beginWhileLoopBody = 132; + EndWhileLoop endWhileLoop = 133; + BeginDoWhileLoopBody beginDoWhileLoopBody = 134; + BeginDoWhileLoopHeader beginDoWhileLoopHeader = 135; + EndDoWhileLoop endDoWhileLoop = 136; + BeginForLoopInitializer beginForLoopInitializer = 137; + BeginForLoopCondition beginForLoopCondition = 138; + BeginForLoopAfterthought beginForLoopAfterthought = 139; + BeginForLoopBody beginForLoopBody = 140; + EndForLoop endForLoop = 141; + BeginForInLoop beginForInLoop = 142; + EndForInLoop endForInLoop = 143; + BeginForOfLoop beginForOfLoop = 144; + BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 145; + EndForOfLoop endForOfLoop = 146; + BeginRepeatLoop beginRepeatLoop = 147; + EndRepeatLoop endRepeatLoop = 148; + LoopBreak loopBreak = 149; + LoopContinue loopContinue = 150; + BeginTry beginTry = 151; + BeginCatch beginCatch = 152; + BeginFinally beginFinally = 153; + EndTryCatchFinally endTryCatchFinally = 154; + ThrowException throwException = 155; + BeginCodeString beginCodeString = 156; + EndCodeString endCodeString = 157; + BeginBlockStatement beginBlockStatement = 158; + EndBlockStatement endBlockStatement = 159; + BeginSwitch beginSwitch = 160; + BeginSwitchCase beginSwitchCase = 161; + BeginSwitchDefaultCase beginSwitchDefaultCase = 162; + EndSwitchCase endSwitchCase = 163; + EndSwitch endSwitch = 164; + SwitchBreak switchBreak = 165; + LoadNewTarget loadNewTarget = 166; + Print print = 167; + Explore explore = 168; + Probe probe = 169; + Fixup fixup = 170; + BeginWasmModule beginWasmModule = 171; + EndWasmModule endWasmModule = 172; + CreateWasmGlobal createWasmGlobal = 173; + CreateWasmMemory createWasmMemory = 174; + CreateWasmTable createWasmTable = 175; + CreateWasmJSTag createWasmJSTag = 176; + CreateWasmTag createWasmTag = 177; + WrapPromising wrapPromising = 178; + WrapSuspending wrapSuspending = 179; + BindMethod bindMethod = 180; + BindFunction bindFunction = 181; + Consti64 consti64 = 182; + Consti32 consti32 = 183; + Constf32 constf32 = 184; + Constf64 constf64 = 185; + WasmReturn wasmReturn = 186; + WasmJsCall wasmJsCall = 187; + Wasmi32CompareOp wasmi32CompareOp = 188; + Wasmi64CompareOp wasmi64CompareOp = 189; + Wasmf32CompareOp wasmf32CompareOp = 190; + Wasmf64CompareOp wasmf64CompareOp = 191; + Wasmi32EqualZero wasmi32EqualZero = 192; + Wasmi64EqualZero wasmi64EqualZero = 193; + Wasmi32BinOp wasmi32BinOp = 194; + Wasmi64BinOp wasmi64BinOp = 195; + Wasmi32UnOp wasmi32UnOp = 196; + Wasmi64UnOp wasmi64UnOp = 197; + Wasmf32BinOp wasmf32BinOp = 198; + Wasmf64BinOp wasmf64BinOp = 199; + Wasmf32UnOp wasmf32UnOp = 200; + Wasmf64UnOp wasmf64UnOp = 201; + WasmWrapi64Toi32 wasmWrapi64Toi32 = 202; + WasmTruncatef32Toi32 wasmTruncatef32Toi32 = 203; + WasmTruncatef64Toi32 wasmTruncatef64Toi32 = 204; + WasmExtendi32Toi64 wasmExtendi32Toi64 = 205; + WasmTruncatef32Toi64 wasmTruncatef32Toi64 = 206; + WasmTruncatef64Toi64 wasmTruncatef64Toi64 = 207; + WasmConverti32Tof32 wasmConverti32Tof32 = 208; + WasmConverti64Tof32 wasmConverti64Tof32 = 209; + WasmDemotef64Tof32 wasmDemotef64Tof32 = 210; + WasmConverti32Tof64 wasmConverti32Tof64 = 211; + WasmConverti64Tof64 wasmConverti64Tof64 = 212; + WasmPromotef32Tof64 wasmPromotef32Tof64 = 213; + WasmReinterpretf32Asi32 wasmReinterpretf32Asi32 = 214; + WasmReinterpretf64Asi64 wasmReinterpretf64Asi64 = 215; + WasmReinterpreti32Asf32 wasmReinterpreti32Asf32 = 216; + WasmReinterpreti64Asf64 wasmReinterpreti64Asf64 = 217; + WasmSignExtend8Intoi32 wasmSignExtend8Intoi32 = 218; + WasmSignExtend16Intoi32 wasmSignExtend16Intoi32 = 219; + WasmSignExtend8Intoi64 wasmSignExtend8Intoi64 = 220; + WasmSignExtend16Intoi64 wasmSignExtend16Intoi64 = 221; + WasmSignExtend32Intoi64 wasmSignExtend32Intoi64 = 222; + WasmTruncateSatf32Toi32 wasmTruncateSatf32Toi32 = 223; + WasmTruncateSatf64Toi32 wasmTruncateSatf64Toi32 = 224; + WasmTruncateSatf32Toi64 wasmTruncateSatf32Toi64 = 225; + WasmTruncateSatf64Toi64 wasmTruncateSatf64Toi64 = 226; + WasmReassign wasmReassign = 227; + WasmDefineGlobal wasmDefineGlobal = 228; + WasmDefineTable wasmDefineTable = 229; + WasmDefineMemory wasmDefineMemory = 230; + WasmDefineDataSegment wasmDefineDataSegment = 231; + WasmLoadGlobal wasmLoadGlobal = 232; + WasmStoreGlobal wasmStoreGlobal = 233; + WasmTableGet wasmTableGet = 234; + WasmTableSet wasmTableSet = 235; + WasmTableSize wasmTableSize = 236; + WasmTableGrow wasmTableGrow = 237; + WasmCallIndirect wasmCallIndirect = 238; + WasmCallDirect wasmCallDirect = 239; + WasmReturnCallDirect wasmReturnCallDirect = 240; + WasmReturnCallIndirect wasmReturnCallIndirect = 241; + WasmMemoryLoad wasmMemoryLoad = 242; + WasmMemoryStore wasmMemoryStore = 243; + WasmAtomicLoad wasmAtomicLoad = 244; + WasmAtomicStore wasmAtomicStore = 245; + WasmAtomicRMW wasmAtomicRMW = 246; + WasmAtomicCmpxchg wasmAtomicCmpxchg = 247; + WasmMemorySize wasmMemorySize = 248; + WasmMemoryGrow wasmMemoryGrow = 249; + WasmMemoryFill wasmMemoryFill = 250; + WasmMemoryInit wasmMemoryInit = 251; + WasmDropDataSegment wasmDropDataSegment = 252; + BeginWasmFunction beginWasmFunction = 253; + EndWasmFunction endWasmFunction = 254; + WasmBeginBlock wasmBeginBlock = 255; + WasmEndBlock wasmEndBlock = 256; + WasmBeginLoop wasmBeginLoop = 257; + WasmEndLoop wasmEndLoop = 258; + WasmBranch wasmBranch = 259; + WasmBranchIf wasmBranchIf = 260; + WasmBranchTable wasmBranchTable = 261; + WasmNop wasmNop = 262; + WasmBeginIf wasmBeginIf = 263; + WasmBeginElse wasmBeginElse = 264; + WasmEndIf wasmEndIf = 265; + WasmBeginTryTable wasmBeginTryTable = 266; + WasmEndTryTable wasmEndTryTable = 267; + WasmBeginTry wasmBeginTry = 268; + WasmBeginCatchAll wasmBeginCatchAll = 269; + WasmBeginCatch wasmBeginCatch = 270; + WasmEndTry wasmEndTry = 271; + WasmBeginTryDelegate wasmBeginTryDelegate = 272; + WasmEndTryDelegate wasmEndTryDelegate = 273; + WasmThrow wasmThrow = 274; + WasmRethrow wasmRethrow = 275; + WasmThrowRef wasmThrowRef = 276; + WasmDefineTag wasmDefineTag = 277; + ConstSimd128 constSimd128 = 278; + WasmSimd128Compare wasmSimd128Compare = 279; + WasmSimd128IntegerUnOp wasmSimd128IntegerUnOp = 280; + WasmSimd128IntegerBinOp wasmSimd128IntegerBinOp = 281; + WasmSimd128IntegerTernaryOp wasmSimd128IntegerTernaryOp = 282; + WasmSimd128FloatUnOp wasmSimd128FloatUnOp = 283; + WasmSimd128FloatBinOp wasmSimd128FloatBinOp = 284; + WasmSimd128FloatTernaryOp wasmSimd128FloatTernaryOp = 285; + WasmSimdSplat wasmSimdSplat = 286; + WasmSimdExtractLane wasmSimdExtractLane = 287; + WasmSimdReplaceLane wasmSimdReplaceLane = 288; + WasmSimdStoreLane wasmSimdStoreLane = 289; + WasmSimdLoadLane wasmSimdLoadLane = 290; + WasmSimdLoad wasmSimdLoad = 291; + WasmUnreachable wasmUnreachable = 292; + WasmSelect wasmSelect = 293; + WasmBeginTypeGroup wasmBeginTypeGroup = 294; + WasmEndTypeGroup wasmEndTypeGroup = 295; + WasmDefineArrayType wasmDefineArrayType = 296; + WasmDefineStructType wasmDefineStructType = 297; + WasmDefineForwardOrSelfReference wasmDefineForwardOrSelfReference = 298; + WasmResolveForwardReference wasmResolveForwardReference = 299; + WasmArrayNewFixed wasmArrayNewFixed = 300; + WasmArrayNewDefault wasmArrayNewDefault = 301; + WasmArrayLen wasmArrayLen = 302; + WasmArrayGet wasmArrayGet = 303; + WasmArraySet wasmArraySet = 304; + WasmStructNewDefault wasmStructNewDefault = 305; + WasmStructGet wasmStructGet = 306; + WasmStructSet wasmStructSet = 307; + WasmRefNull wasmRefNull = 308; + WasmRefIsNull wasmRefIsNull = 309; + WasmRefI31 wasmRefI31 = 310; + WasmI31Get wasmI31Get = 311; + WasmAnyConvertExtern wasmAnyConvertExtern = 312; + WasmExternConvertAny wasmExternConvertAny = 313; + WasmMemoryCopy wasmMemoryCopy = 314; + WasmDefineElementSegment wasmDefineElementSegment = 315; + WasmTableInit wasmTableInit = 316; + WasmDropElementSegment wasmDropElementSegment = 317; + WasmTableCopy wasmTableCopy = 318; + WasmDefineSignatureType wasmDefineSignatureType = 319; + CreateNamedDisposableVariable createNamedDisposableVariable = 320; + CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 321; + WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 322; + WasmStructNew wasmStructNew = 323; + WasmRefEq wasmRefEq = 324; + WasmRefTest wasmRefTest = 325; + WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 326; + WasmRefCast wasmRefCast = 327; } } From 7e5724ccc4551bf54773cb14450dc6f65c01f6ae Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 16:25:55 +0100 Subject: [PATCH 004/223] [wasm] Simplify Table.get/set The TableType will need to be adapted for tracking wasm-gc signatures. I just couldn't find a good reason why we'd need to store the TableType on Table.get and Table.set? Bug: 445356784 Change-Id: Ia115d287b27cc18f52a48ddce25b897f1a19b293 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123736 Reviewed-by: Manos Koukoutos Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 34 ++--- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 7 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 13 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 123 +----------------- Sources/Fuzzilli/Protobuf/operations.proto | 9 -- 6 files changed, 22 insertions(+), 168 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index aea8a1c5f..73b2d8258 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3747,14 +3747,14 @@ public class ProgramBuilder { public func wasmTableGet(tableRef: Variable, idx: Variable) -> Variable { let tableType = b.type(of: tableRef) let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGet(tableType: tableType), withInputs: [tableRef, idx], types: [tableType, offsetType]).output + return b.emit(WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType]).output } public func wasmTableSet(tableRef: Variable, idx: Variable, to value: Variable) { let tableType = b.type(of: tableRef) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableSet(tableType: tableType), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) + b.emit(WasmTableSet(), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) } @discardableResult diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 2ea23a453..ccf98f9f6 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1258,24 +1258,10 @@ extension Instruction: ProtobufConvertible { $0.wasmStoreGlobal = Fuzzilli_Protobuf_WasmStoreGlobal.with { $0.globalType = ILTypeToWasmTypeEnum(op.globalType) } - case .wasmTableGet(let op): - $0.wasmTableGet = Fuzzilli_Protobuf_WasmTableGet.with { - $0.elementType = ILTypeToWasmTypeEnum(op.tableType.elementType) - $0.minSize = Int64(op.tableType.limits.min) - if let max = op.tableType.limits.max { - $0.maxSize = Int64(max) - } - $0.isTable64 = op.tableType.isTable64 - } - case .wasmTableSet(let op): - $0.wasmTableSet = Fuzzilli_Protobuf_WasmTableSet.with { - $0.elementType = ILTypeToWasmTypeEnum(op.tableType.elementType) - $0.minSize = Int64(op.tableType.limits.min) - if let max = op.tableType.limits.max { - $0.maxSize = Int64(max) - } - $0.isTable64 = op.tableType.isTable64 - } + case .wasmTableGet(_): + $0.wasmTableGet = Fuzzilli_Protobuf_WasmTableGet() + case .wasmTableSet(_): + $0.wasmTableSet = Fuzzilli_Protobuf_WasmTableSet() case .wasmCallIndirect(let op): $0.wasmCallIndirect = Fuzzilli_Protobuf_WasmCallIndirect.with { $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) @@ -2340,14 +2326,10 @@ extension Instruction: ProtobufConvertible { op = WasmLoadGlobal(globalType: WasmTypeEnumToILType(p.globalType)) case .wasmStoreGlobal(let p): op = WasmStoreGlobal(globalType: WasmTypeEnumToILType(p.globalType)) - case .wasmTableGet(let p): - op = WasmTableGet(tableType: .wasmTable(wasmTableType: - WasmTableType(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), isTable64: p.isTable64, knownEntries: []))) - case .wasmTableSet(let p): - op = WasmTableSet(tableType: .wasmTable(wasmTableType: - WasmTableType(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), isTable64: p.isTable64, knownEntries: []))) + case .wasmTableGet(_): + op = WasmTableGet() + case .wasmTableSet(_): + op = WasmTableSet() case .wasmCallIndirect(let p): let parameters = p.parameterTypes.map(WasmTypeEnumToILType) let outputs = p.outputTypes.map(WasmTypeEnumToILType) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 584572320..331599b2d 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -768,10 +768,11 @@ public struct JSTyper: Analyzer { case .wasmStoreGlobal(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - case .wasmTableGet(let op): + case .wasmTableGet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - setType(of: instr.output, to: op.tableType.elementType) + let tableType = type(of: instr.input(0)) + dynamicObjectGroupManager.addWasmTable(withType: tableType, forDefinition: definingInstruction, forVariable: instr.input(0)) + setType(of: instr.output, to: tableType.wasmTableType!.elementType) case .wasmTableSet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 55d3b16c0..f707d1ce9 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -912,12 +912,7 @@ final class WasmStoreGlobal: WasmOperation { final class WasmTableGet: WasmOperation { override var opcode: Opcode { .wasmTableGet(self) } - let tableType: WasmTableType - - init(tableType: ILType) { - assert(tableType.isWasmTableType) - self.tableType = tableType.wasmTableType! - + init() { super.init(numInputs: 2, numOutputs: 1, requiredContext: [.wasmFunction]) } } @@ -925,11 +920,7 @@ final class WasmTableGet: WasmOperation { final class WasmTableSet: WasmOperation { override var opcode: Opcode { .wasmTableSet(self) } - let tableType: WasmTableType - - init(tableType: ILType) { - assert(tableType.isWasmTableType) - self.tableType = tableType.wasmTableType! + init() { super.init(numInputs: 3, requiredContext: [.wasmFunction]) } } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 1ae44b73e..90e194e63 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4754,40 +4754,14 @@ public struct Fuzzilli_Protobuf_WasmStoreGlobal: Sendable { fileprivate var _globalType: Fuzzilli_Protobuf_WasmILType? = nil } -/// WasmTableGet and WasmTableSet need a WasmTableType as input. public struct Fuzzilli_Protobuf_WasmTableGet: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var elementType: Fuzzilli_Protobuf_WasmILType { - get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {self._elementType != nil} - /// Clears the value of `elementType`. Subsequent reads from it will return its default value. - public mutating func clearElementType() {self._elementType = nil} - - public var minSize: Int64 = 0 - - public var maxSize: Int64 { - get {_maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {self._maxSize != nil} - /// Clears the value of `maxSize`. Subsequent reads from it will return its default value. - public mutating func clearMaxSize() {self._maxSize = nil} - - public var isTable64: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _elementType: Fuzzilli_Protobuf_WasmILType? = nil - fileprivate var _maxSize: Int64? = nil } public struct Fuzzilli_Protobuf_WasmTableSet: Sendable { @@ -4795,34 +4769,9 @@ public struct Fuzzilli_Protobuf_WasmTableSet: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var elementType: Fuzzilli_Protobuf_WasmILType { - get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {self._elementType != nil} - /// Clears the value of `elementType`. Subsequent reads from it will return its default value. - public mutating func clearElementType() {self._elementType = nil} - - public var minSize: Int64 = 0 - - public var maxSize: Int64 { - get {_maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {self._maxSize != nil} - /// Clears the value of `maxSize`. Subsequent reads from it will return its default value. - public mutating func clearMaxSize() {self._maxSize = nil} - - public var isTable64: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _elementType: Fuzzilli_Protobuf_WasmILType? = nil - fileprivate var _maxSize: Int64? = nil } public struct Fuzzilli_Protobuf_WasmTableSize: Sendable { @@ -12732,48 +12681,18 @@ extension Fuzzilli_Protobuf_WasmStoreGlobal: SwiftProtobuf.Message, SwiftProtobu extension Fuzzilli_Protobuf_WasmTableGet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmTableGet" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}elementType\0\u{1}minSize\0\u{1}maxSize\0\u{1}isTable64\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._elementType) }() - case 2: try { try decoder.decodeSingularInt64Field(value: &self.minSize) }() - case 3: try { try decoder.decodeSingularInt64Field(value: &self._maxSize) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.isTable64) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._elementType { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if self.minSize != 0 { - try visitor.visitSingularInt64Field(value: self.minSize, fieldNumber: 2) - } - try { if let v = self._maxSize { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 3) - } }() - if self.isTable64 != false { - try visitor.visitSingularBoolField(value: self.isTable64, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmTableGet, rhs: Fuzzilli_Protobuf_WasmTableGet) -> Bool { - if lhs._elementType != rhs._elementType {return false} - if lhs.minSize != rhs.minSize {return false} - if lhs._maxSize != rhs._maxSize {return false} - if lhs.isTable64 != rhs.isTable64 {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -12781,48 +12700,18 @@ extension Fuzzilli_Protobuf_WasmTableGet: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmTableSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmTableSet" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}elementType\0\u{1}minSize\0\u{1}maxSize\0\u{1}isTable64\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._elementType) }() - case 2: try { try decoder.decodeSingularInt64Field(value: &self.minSize) }() - case 3: try { try decoder.decodeSingularInt64Field(value: &self._maxSize) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.isTable64) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._elementType { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if self.minSize != 0 { - try visitor.visitSingularInt64Field(value: self.minSize, fieldNumber: 2) - } - try { if let v = self._maxSize { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 3) - } }() - if self.isTable64 != false { - try visitor.visitSingularBoolField(value: self.isTable64, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmTableSet, rhs: Fuzzilli_Protobuf_WasmTableSet) -> Bool { - if lhs._elementType != rhs._elementType {return false} - if lhs.minSize != rhs.minSize {return false} - if lhs._maxSize != rhs._maxSize {return false} - if lhs.isTable64 != rhs.isTable64 {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 1be3ee744..4699a27f0 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1097,19 +1097,10 @@ message WasmStoreGlobal { WasmILType globalType = 2; } -// WasmTableGet and WasmTableSet need a WasmTableType as input. message WasmTableGet { - WasmILType elementType = 1; - int64 minSize = 2; - optional int64 maxSize = 3; - bool isTable64 = 4; } message WasmTableSet { - WasmILType elementType = 1; - int64 minSize = 2; - optional int64 maxSize = 3; - bool isTable64 = 4; } message WasmTableSize { From 2ae06c9a1917ddacaf09cef5bbc6b7ccbfe4e8c1 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 19:12:24 +0100 Subject: [PATCH 005/223] [wasm] Don't emit empty module sections Change-Id: I99bc88a3cefdd5d4cbaf645b10e1cdcd66138a52 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123977 Commit-Queue: Manos Koukoutos Reviewed-by: Manos Koukoutos Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Lifting/WasmLifter.swift | 72 +++++++++++++++-------- Tests/FuzzilliTests/LifterTest.swift | 18 ++++++ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 5a3f391dc..c3e880992 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -622,10 +622,6 @@ public class WasmLifter { } private func buildTypeSection() throws { - self.bytecode += [WasmSection.type.rawValue] - - var temp = Data() - // Collect all signatures of imported functions, suspendable objects or tags. // See importAnalysis for more details. for signature in self.exports.compactMap({ $0.getImport()?.signature }) { @@ -638,7 +634,12 @@ public class WasmLifter { } let typeCount = self.signatures.count + typeGroups.count - temp += Leb128.unsignedEncode(typeCount) + if typeCount == 0 { + return + } + + self.bytecode += [WasmSection.type.rawValue] + var temp = Leb128.unsignedEncode(typeCount) // TODO(mliedtke): Integrate this with the whole signature mechanism as // these signatures could contain wasm-gc types. @@ -791,11 +792,16 @@ public class WasmLifter { } private func buildFunctionSection() throws { + let functionCount = self.exports.count { $0.isFunction } + if functionCount == 0 { + return + } + self.bytecode += [WasmSection.function.rawValue] // The number of functions we have, as this is a vector of type idxs. // TODO(cffsmith): functions can share type indices. This could be an optimization later on. - var temp = Leb128.unsignedEncode(self.exports.count { $0.isFunction }) + var temp = Leb128.unsignedEncode(functionCount) for case let .function(functionInfo) in self.exports { temp.append(Leb128.unsignedEncode(try getSignatureIndex(functionInfo!.signature))) @@ -814,9 +820,14 @@ public class WasmLifter { } private func buildTableSection() throws { + let tableCount = self.exports.count { $0.isTable } + if tableCount == 0 { + return + } + self.bytecode += [WasmSection.table.rawValue] - var temp = Leb128.unsignedEncode(self.exports.count { $0.isTable }) + var temp = Leb128.unsignedEncode(tableCount) for case let .table(instruction) in self.exports { let op = instruction!.op as! WasmDefineTable @@ -922,9 +933,13 @@ public class WasmLifter { } private func buildCodeSection(_ instructions: Code) throws { + let functionCount = self.exports.count { $0.isFunction } + if functionCount == 0 { + return + } + // Build the contents of the section - var temp = Data() - temp += Leb128.unsignedEncode(self.exports.count { $0.isFunction }) + var temp = Leb128.unsignedEncode(functionCount) var functionBranchHints = [Data]() @@ -1006,6 +1021,10 @@ public class WasmLifter { } private func buildDataSection() throws { + if self.dataSegments.isEmpty { + return + } + self.bytecode += [WasmSection.data.rawValue] var temp = Data() @@ -1030,11 +1049,12 @@ public class WasmLifter { } private func buildDataCountSection() throws { - self.bytecode += [WasmSection.datacount.rawValue] - - var temp = Data() - temp += Leb128.unsignedEncode(self.dataSegments.count) + if self.dataSegments.isEmpty { + return + } + self.bytecode += [WasmSection.datacount.rawValue] + let temp = Leb128.unsignedEncode(self.dataSegments.count) self.bytecode.append(Leb128.unsignedEncode(temp.count)) self.bytecode.append(temp) @@ -1047,11 +1067,13 @@ public class WasmLifter { } private func buildGlobalSection() throws { - self.bytecode += [WasmSection.global.rawValue] - - var temp = Data() + let globalCount = self.exports.count { $0.isGlobal } + if globalCount == 0 { + return + } - temp += Leb128.unsignedEncode(self.exports.count { $0.isGlobal }) + self.bytecode += [WasmSection.global.rawValue] + var temp = Leb128.unsignedEncode(globalCount) // TODO: in the future this should maybe be a context that allows instructions? Such that we can fuzz this expression as well? for case let .global(instruction) in self.exports { @@ -1102,13 +1124,13 @@ public class WasmLifter { } private func buildMemorySection() { - self.bytecode += [WasmSection.memory.rawValue] - - var temp = Data() + let memoryCount = self.exports.count { $0.isMemory } + if memoryCount == 0 { + return + } - // The amount of memories we have, per standard this can currently only be one, either defined or imported - // https://webassembly.github.io/spec/core/syntax/modules.html#memories - temp += Leb128.unsignedEncode(self.exports.count { $0.isMemory }) + self.bytecode += [WasmSection.memory.rawValue] + var temp = Leb128.unsignedEncode(memoryCount) for case let .memory(instruction) in self.exports { let type = typer.type(of: instruction!.output) @@ -1164,6 +1186,10 @@ public class WasmLifter { // Export all imports and defined things by default. private func buildExportedSection() throws { + if self.exports.isEmpty { + return + } + self.bytecode += [WasmSection.export.rawValue] var temp = Data() diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 9ab5912db..8f3b5e6fc 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3897,4 +3897,22 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testEmptyWasmModule() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + b.buildWasmModule {_ in} + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + // An empty Wasm module should only contain the needed prefix but no empty sections. + let expected = """ + const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ]))); + + """ + + XCTAssertEqual(actual, expected) + } } From 6bac790345a42dc2b6ae295b13798d8641ab9410 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 18:30:44 +0100 Subject: [PATCH 006/223] [wasm] Add code generator producing an exnref The WasmThrowRefGenerator requires an exnref as an input. Without having a generator that produces it, it isn't very likely that there is an exnref available in the current program, so the generator cannot be run in most cases. Registering a generator producing that exnref (if a tag is available) helps significantly. Change-Id: Idbd9337f5a7339d58fe1f76e264569907f7081ce Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123976 Auto-Submit: Matthias Liedtke Reviewed-by: Manos Koukoutos Commit-Queue: Manos Koukoutos --- .../CodeGen/CodeGeneratorWeights.swift | 3 +++ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 24 +++++++++++++++++++ Tests/FuzzilliTests/ProgramBuilderTest.swift | 1 + 3 files changed, 28 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 32540cfc0..aa026f062 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -324,6 +324,9 @@ public let codeGeneratorWeights = [ "WasmLegacyTryDelegateGenerator": 8, "WasmThrowGenerator": 2, "WasmLegacyRethrowGenerator": 10, + // This generator is mostly just there, so that the WasmThrowRefGenerator + // can create an exnref on demand (if a wasm tag is present). + "WasmCreateExnRefGenerator": 1, "WasmThrowRefGenerator": 6, "WasmBranchGenerator": 6, "WasmBranchIfGenerator": 6, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 5077ac26a..b6050f5ea 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1620,6 +1620,30 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLegacyRethrow(exception) }, + CodeGenerator( + "WasmCreateExnRefGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmTag")), + produces: [.wasmExnRef()] + ) { b, tag in + let function = b.currentWasmModule.currentWasmFunction + let tagType = b.type(of: tag).wasmTagType! + guard !tagType.isJSTag else { + // We can't throw a JSTag, so simply create a null value. + function.wasmRefNull(type: .wasmExnRef()) + return + } + // Create a try-catch throwing and catching a tag producing an exnref as + // a result. + function.wasmBuildBlockWithResults(with: [] => (tagType.parameters + [.wasmExnRef()]), args: []) { label, _ in + let args = tagType.parameters.map(function.findOrGenerateWasmVar) + function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { _, _ in + function.WasmBuildThrow(tag: tag, inputs: args) + return [] + } + return args + [function.wasmRefNull(type: .wasmExnRef())] + } + }, + CodeGenerator( "WasmThrowRefGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExnRef()) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 69ef921eb..5f495f0dc 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3125,6 +3125,7 @@ class ProgramBuilderTests: XCTestCase { test("WasmStructNewDefaultGenerator", expectAny: WasmStructNewDefault.self) test("WasmArrayGetGenerator", expectAny: WasmArrayGet.self, requiresTypes: true) test("WasmStructGetGenerator", expectAny: WasmStructGet.self, requiresTypes: true) + test("WasmThrowRefGenerator", expectAny: WasmThrowRef.self) } func testThatGeneratorsExistAndAreBuildableFromJs() { From 7fb825472f1aefd0fca63ea80948d6fac02d41f3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 23 Mar 2026 13:52:37 +0100 Subject: [PATCH 007/223] [wasm] Properly fix typing issue in WasmBeginCatch The first attempt of fixing this was commit 89691a13e737f342f68dcd19f7ca66a71892d8fc, however this means we might end up not typing the inner outputs (the tag's "elements" available inside the catch) which breaks the typer's assumptions that everything gets typed. Typing it with some dummy value can also lead to issues downstream (e.g. by the next instruction taking now an input that isn't of the needed type any more), so instead we solve this issue by always also adding a signature as an input. As the signature is defined in Wasm, input replacement can only happen with strict type checks, so it is safe to rely on this. It's a bit annoying for the WasmBeginCatch to take an extra input for this specific problem, however, WasmBeginCatch is anyways related to the "legacy" exception handling which isn't a properly spec'ed Wasm feature but a "browsers have been shipping this without a finished spec" kind of thing. Bug: 448860865 Change-Id: I06638ccbb5ed0c9dbb7355ac198b7ace25f521b8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9129497 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 32 ++++++++++++++++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 12 +++----- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 4 +-- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 73b2d8258..aa1127564 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4092,18 +4092,28 @@ public class ProgramBuilder { catchAllBody: ((Variable) -> Void)? = nil) { let signature = [] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + + // Define tag signatures before the try block so they don't interfere with the try/catch + // bodies and their scoping. + // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc + // signature. + let tagSignatures = catchClauses.map { + b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + } + let instr = b.emit(WasmBeginTry( parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) assert(instr.innerOutputs.count == 1) body(instr.innerOutput(0)) - for (tag, generator) in catchClauses { + for (i, (tag, generator)) in catchClauses.enumerated() { b.reportErrorIf(!b.type(of: tag).isWasmTagType, "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + let tagSignatureDef = tagSignatures[i] let instr = b.emit(WasmBeginCatch( blockOutputCount: signature.outputTypes.count, labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), - withInputs: [signatureDef, tag], - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes) + withInputs: [signatureDef, tag, tagSignatureDef], + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody { @@ -4125,18 +4135,28 @@ public class ProgramBuilder { catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = [], catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] { let parameterCount = signature.parameterTypes.count + + // Define tag signatures before the try block so they don't interfere with the try/catch + // bodies and their scoping. + // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc + // signature. + let tagSignatures = catchClauses.map { + b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + } + let instr = b.emit(WasmBeginTry(parameterCount: parameterCount), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) var result = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - for (tag, generator) in catchClauses { + for (i, (tag, generator)) in catchClauses.enumerated() { b.reportErrorIf(!b.type(of: tag).isWasmTagType, "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + let tagSignatureDef = tagSignatures[i] let instr = b.emit(WasmBeginCatch( blockOutputCount: signature.outputTypes.count, labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), - withInputs: [signatureDef, tag] + result, - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes) + withInputs: [signatureDef, tag, tagSignatureDef] + result, + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody = catchAllBody { diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 331599b2d..7741151a6 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -883,13 +883,11 @@ public struct JSTyper: Analyzer { // exception with the legacy exception handling proposal. (This is similar to the // exnref in the standard exception handling spec.) setType(of: instr.innerOutput(1), to: .exceptionLabel) - // Type the tag parameters. - // If the input isn't typed as a Wasm tag any more (this can happen as tags can be - // defined in JS and there a reassign as part of a CodeGenMutator run can loosen the - // inferred type), just act as if there weren't any label parameters. In that case - // the lifter will fail and the test case will be discarded. - let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters ?? [] - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), labelParameters) { + // Type the tag parameters based on the tag's signature definition. + // This guarantees that the inner outputs are properly typed, even if a mutator + // changed the tag variable to something that's not typed as a Wasm tag anymore. + let tagSignature = type(of: instr.input(2)).wasmFunctionSignatureDefSignature + for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) { setType(of: innerOutput, to: paramType) } for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) { diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index f707d1ce9..586c953cd 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1408,9 +1408,9 @@ final class WasmBeginCatch : WasmOperation { // the usage. For now, we just emit a label for branching and the ".exceptionLabel" for // rethrows. super.init( - // Inputs: The block signature, the tag and the outputs of the preceding try or catch + // Inputs: The block signature, the tag, the tag signature, and the outputs of the preceding try or catch // (all) block. - numInputs: 2 + blockOutputCount, + numInputs: 3 + blockOutputCount, // Inner outputs are the branch label, the exception label and the tag parameters. numInnerOutputs: 2 + labelParameterCount, attributes: [ From 323565215d33ef39d0896660abe76da636a092fe Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 23 Mar 2026 18:59:39 +0100 Subject: [PATCH 008/223] [wasm] Fix serialization of WasmBeginCatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue was introduced with commit 7fb825472f1aefd0fca63ea80948d6fac02d41f3 While I was running the fuzzer for multiple hours, the fuzzer is more persmissive in not crashing on invalid programs send over the wire, so this wasn't detected. Change-Id: I34f04902915539cb688c5c6eb6825d28a123ccb0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9130176 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke Reviewed-by: Olivier Flückiger --- Sources/Fuzzilli/FuzzIL/Instruction.swift | 2 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ccf98f9f6..f6c5c093e 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -2532,7 +2532,7 @@ extension Instruction: ProtobufConvertible { } guard op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count else { - throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs") + throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs for operation \(op)") } opCache?.add(op) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 586c953cd..cc9daa405 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1421,7 +1421,7 @@ final class WasmBeginCatch : WasmOperation { requiredContext: [.wasmFunction]) } - var blockOutputCount: Int {numInputs - 2} + var blockOutputCount: Int {numInputs - 3} var labelParameterCount: Int {numInnerOutputs - 2} } From 810796a4a011511e7849445dfbfa1c604163a329 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 24 Mar 2026 14:42:42 +0100 Subject: [PATCH 009/223] [github] Update node.js version for CI Change-Id: I6a3f252f20742dac630864ab4b07e493dbde46ec Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9133476 Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 2d630a4a3..bc70a382b 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/setup-node@v4 with: - node-version: 25-nightly + node-version: 26-nightly - name: Swift Version run: swift --version - uses: actions/checkout@v2 From 506d593d3aa600f1692822e38e09c8556d2d396a Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Wed, 25 Mar 2026 12:13:28 +0100 Subject: [PATCH 010/223] Support more property names Similar to method names, this supports all allowed ways to define properties. Approximated valid identifiers will be used as is, everything else will be quoted, except positive integers. Since such a property can leak into the type information of an object or class, also all property accesses are adapted now, similar to method calls. This also refactors the import of object fields and methods, unifying the same property-key logic used in class definitions. Computed getters and setters for object literals and classes are still a TODO. This also lifts some restrictions from runtime assisted mutators, which previously only allowed simple identifiers as property names. Bug: 446634535 Change-Id: I35a65c0073fee9bac238205557958e80c60e1186 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9111376 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Compiler.swift | 77 ++-- Sources/Fuzzilli/Compiler/Parser/parser.js | 30 +- .../Environment/JavaScriptEnvironment.swift | 16 +- .../Lifting/JavaScriptExploreLifting.swift | 2 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 47 ++- .../Lifting/JavaScriptProbeLifting.swift | 2 +- ...aScriptRuntimeAssistedMutatorLifting.swift | 18 +- .../Fuzzilli/Mutators/ProbingMutator.swift | 12 - Sources/Fuzzilli/Protobuf/ast.pb.swift | 336 ++++-------------- Sources/Fuzzilli/Protobuf/ast.proto | 38 +- .../computed_and_indexed_properties.js | 73 ++++ Tests/FuzzilliTests/LifterTest.swift | 195 ++++++++-- 12 files changed, 409 insertions(+), 437 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index d8a4def6e..5a6d5be9e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -774,15 +774,21 @@ public class JavaScriptCompiler { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in object expression") } - if case .property(let property) = field { - propertyValues.append(try compileExpression(property.value)) - if case .expression(let expression) = property.key { - computedKeys.append(try compileExpression(expression)) - } - } else if case .method(let method) = field { - if case .expression(let expression) = method.key { - computedKeys.append(try compileExpression(expression)) - } + + let key : Compiler_Protobuf_PropertyKey + switch field { + case .property(let property): + propertyValues.append(try compileExpression(property.value)) + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key + } + if case .expression(let expression) = key.body { + computedKeys.append(try compileExpression(expression)) } } @@ -795,7 +801,7 @@ public class JavaScriptCompiler { for field in objectExpression.fields { switch field.field! { case .property(let property): - guard let key = property.key else { + guard let key = property.key.body else { throw CompilerError.invalidNodeError("missing key in object expression field") } let inputs = [propertyValues.removeLast()] @@ -809,16 +815,22 @@ public class JavaScriptCompiler { } case .method(let method): let parameters = convertParameters(method.parameters) + let head: Instruction - let instr: Instruction - if case .name(let name) = method.key { - instr = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) - } else { - instr = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) + guard let key = method.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression method") + } + switch key { + case .name(let name): + head = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + case .index(let index): + head = emit(BeginObjectLiteralMethod(methodName: String(index), parameters: parameters)) + case .expression: + head = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) } try enterNewScope { - var parameters = instr.innerOutputs + var parameters = head.innerOutputs map("this", to: parameters.removeFirst()) mapParameters(method.parameters, to: parameters) for statement in method.body { @@ -826,30 +838,47 @@ public class JavaScriptCompiler { } } - if case .name = method.key { + switch key { + case .name, .index: emit(EndObjectLiteralMethod()) - } else { + case .expression: emit(EndObjectLiteralComputedMethod()) } case .getter(let getter): - guard case .name(let name) = getter.key else { + guard let key = getter.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression getter") + } + let head: Instruction + switch key { + case .name(let name): + head = emit(BeginObjectLiteralGetter(propertyName: name)) + case .index(let index): + head = emit(BeginObjectLiteralGetter(propertyName: String(index))) + case .expression: fatalError("Computed getters are not yet supported") } - let instr = emit(BeginObjectLiteralGetter(propertyName: name)) try enterNewScope { - map("this", to: instr.innerOutput) + map("this", to: head.innerOutput) for statement in getter.body { try compileStatement(statement) } } emit(EndObjectLiteralGetter()) case .setter(let setter): - guard case .name(let name) = setter.key else { + guard let key = setter.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression setter") + } + let head: Instruction + switch key { + case .name(let name): + head = emit(BeginObjectLiteralSetter(propertyName: name)) + case .index(let index): + head = emit(BeginObjectLiteralSetter(propertyName: String(index))) + case .expression: fatalError("Computed setters are not yet supported") } - let instr = emit(BeginObjectLiteralSetter(propertyName: name)) try enterNewScope { - var parameters = instr.innerOutputs + var parameters = head.innerOutputs map("this", to: parameters.removeFirst()) map(setter.parameter.name, to: parameters.removeFirst()) assert(parameters.isEmpty) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 4c5eaace1..0e8b24d16 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -164,7 +164,7 @@ function parse(script, proto) { } else if (member.key.type === 'StringLiteral') { body.name = member.key.value; } else { - throw "Unknown member key type: " + member.key.type + " in class declaration"; + throw "Unknown member key type: " + member.key.type + " in declaration"; } } return make('PropertyKey', body); @@ -468,19 +468,7 @@ function parse(script, proto) { assert(!field.method, "Expected field.method to be false"); let property = {}; property.value = visitExpression(field.value); - if (field.computed) { - property.expression = visitExpression(field.key); - } else { - if (field.key.type === 'Identifier') { - property.name = field.key.name; - } else if (field.key.type === 'NumericLiteral') { - property.index = field.key.value; - } else if (field.key.type === 'StringLiteral') { - property.name = field.key.value; - } else { - throw "Unknown property key type: " + field.key.type; - } - } + property.key = visitMemberKey(field); fields.push(make('ObjectField', { property: make('ObjectProperty', property) })); } else { assert(field.type === 'ObjectMethod', "Expected field.type to be exactly 'ObjectMethod'"); @@ -489,19 +477,7 @@ function parse(script, proto) { let method = field; let out = {}; - if (method.computed) { - out.expression = visitExpression(method.key); - } else { - if (method.key.type === 'Identifier') { - out.name = method.key.name; - } else if (method.key.type === 'NumericLiteral') { - out.name = String(method.key.value); - } else if (method.key.type === 'StringLiteral') { - out.name = method.key.value; - } else { - throw "Unknown method key type: " + method.key.type; - } - } + out.key = visitMemberKey(method); field = {}; if (method.kind === 'method') { diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 87c572104..9461bd760 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -291,7 +291,7 @@ public class JavaScriptEnvironment: ComponentBase { public let interestingRegExpQuantifiers = ["*", "+", "?"] /// Identifiers that should be used for custom properties and methods. - public static let CustomPropertyNames = ["a", "b", "c", "d", "e", "f", "g", "h"] + public static let CustomPropertyNames = ["a", "b", "c", "d", "e", "f", "!", "42"] public static let CustomMethodNames = ["m", "n", "o", "?", "67", "valueOf", "toString"] public static let CustomPrivateMethodNames = ["m", "n", "o", "p"] @@ -318,13 +318,13 @@ public class JavaScriptEnvironment: ComponentBase { private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] - private let validMethodDefinitionName: Regex? + private let validIdentifierOrIndex: Regex? private let validDotNotationName: Regex? private let validPropertyIndex: Regex? public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { // A simple approximation of a valid JS identifier (used in dot - // notation and for method definitions). + // notation and for property and method names). let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" // A non-negative integer (with no leading zero) for index access @@ -334,10 +334,10 @@ public class JavaScriptEnvironment: ComponentBase { // Initialize regular expressions to determine valid property // identifiers: - // At method definition site, we support simple identifiers and - // non-negative numbers. Other names will be quoted. + // We support simple identifiers and non-negative numbers. Other + // names will be quoted. // We don't support unquoted doubles. - self.validMethodDefinitionName = try! Regex("^(\(index)|\(simpleId))$") + self.validIdentifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") // For dot notation we only support simple identifiers. We don't // support all possible names according to JS spec. @@ -1004,8 +1004,8 @@ public class JavaScriptEnvironment: ComponentBase { } } - func isValidNameForMethodDefinition(_ name: String) -> Bool { - return (try? validMethodDefinitionName?.wholeMatch(in: name)) != nil + func isValidIdentifierOrIndex(_ name: String) -> Bool { + return (try? validIdentifierOrIndex?.wholeMatch(in: name)) != nil } func isValidDotNotationName(_ name: String) -> Bool { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index 1863c08b0..835263b95 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -329,7 +329,7 @@ struct JavaScriptExploreLifting { function exploreString(s) { // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. // TODO: sometimes access a character of the string or iterate over it? - if (probability(0.1) && isSimpleString(s)) { + if (probability(0.1) && isShortString(s)) { return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); } else { return exploreObject(new String(s)); diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 680e77f47..0fc5d343a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -383,9 +383,8 @@ public class JavaScriptLifter: Lifter { w.pushTemporaryOutputBuffer(initialIndentionLevel: 0) case .objectLiteralAddProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let VALUE = input(0) - assert(!PROPERTY.contains(" ")) currentObjectLiteral.addField("\(PROPERTY): \(VALUE)") case .objectLiteralAddElement(let op): @@ -409,7 +408,7 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) + let METHOD = quoteIdentifierIfNeeded(op.methodName) currentObjectLiteral.beginMethod("\(METHOD)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -428,7 +427,7 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralGetter(let op): assert(instr.numInnerOutputs == 1) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) currentObjectLiteral.beginMethod("get \(PROPERTY)() {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -436,7 +435,7 @@ public class JavaScriptLifter: Lifter { assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) currentObjectLiteral.beginMethod("set \(PROPERTY)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -497,7 +496,7 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .classAddProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) @@ -538,7 +537,7 @@ public class JavaScriptLifter: Lifter { case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) + let METHOD = quoteIdentifierIfNeeded(op.methodName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") w.enterNewBlock() @@ -554,7 +553,7 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .beginClassGetter(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)get \(PROPERTY)() {") w.enterNewBlock() @@ -564,7 +563,7 @@ public class JavaScriptLifter: Lifter { assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)set \(PROPERTY)(\(PARAMS)) {") w.enterNewBlock() @@ -655,29 +654,27 @@ public class JavaScriptLifter: Lifter { case .getProperty(let op): let obj = input(0) - let accessOperator = op.isGuarded ? "?." : "." - let expr = MemberExpression.new() + obj + accessOperator + op.propertyName + let expr = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) w.assign(expr, to: instr.output) case .setProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of an assignment, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let PROPERTY = MemberExpression.new() + obj + "." + op.propertyName + let PROPERTY = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName)) let VALUE = input(1) w.emit("\(PROPERTY) = \(VALUE);") case .updateProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of an assignment, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let PROPERTY = MemberExpression.new() + obj + "." + op.propertyName + let PROPERTY = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName)) let VALUE = input(1) w.emit("\(PROPERTY) \(op.op.token)= \(VALUE);") case .deleteProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of a property deletion, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let accessOperator = op.isGuarded ? "?." : "." - let target = MemberExpression.new() + obj + accessOperator + op.propertyName + let target = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) let expr = UnaryExpression.new() + "delete " + target w.assign(expr, to: instr.output) @@ -1111,13 +1108,13 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .getSuperProperty(let op): - let expr = MemberExpression.new() + "super.\(op.propertyName)" + let expr = MemberExpression.new() + "super" + liftMemberAccess(op.propertyName) w.assign(expr, to: instr.output) case .setSuperProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = liftMemberAccess(op.propertyName) let VALUE = input(0) - w.emit("super.\(PROPERTY) = \(VALUE);") + w.emit("super\(PROPERTY) = \(VALUE);") case .getComputedSuperProperty(_): let expr = MemberExpression.new() + "super[" + input(0).text + "]" @@ -1129,9 +1126,9 @@ public class JavaScriptLifter: Lifter { w.emit("super[\(PROPERTY)] = \(VALUE);") case .updateSuperProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = liftMemberAccess(op.propertyName) let VALUE = input(0) - w.emit("super.\(PROPERTY) \(op.op.token)= \(VALUE);") + w.emit("super\(PROPERTY) \(op.op.token)= \(VALUE);") case .beginIf(let op): var COND = input(0) @@ -1804,19 +1801,19 @@ public class JavaScriptLifter: Lifter { } } - func quoteMethodDefinitionIfNeeded(_ name: String) -> String { - if environment.isValidNameForMethodDefinition(name) { + func quoteIdentifierIfNeeded(_ name: String) -> String { + if environment.isValidIdentifierOrIndex(name) { return name } return "\"\(name)\"" } - private func liftMemberAccess(_ name: String) -> String { + private func liftMemberAccess(_ name: String, isGuarded: Bool = false) -> String { if environment.isValidDotNotationName(name){ - return "." + name + return (isGuarded ? "?." : ".") + name } let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" - return "[" + safeName + "]" + return (isGuarded ? "?." : "") + "[" + safeName + "]" } private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift index 071c4d8c5..c5347505a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift @@ -64,7 +64,7 @@ struct JavaScriptProbeLifting { } } - if (!isSimpleString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { + if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { // Cannot deal with this property name. Ignore it. return; } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index 6f9882ad8..a1e1a0d69 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -134,12 +134,10 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; } - // Helper function to determine if a string is "simple". We only include simple strings for property/method names or string literals. - // A simple string is basically a valid, property name with a maximum length. - const simpleStringRegExp = /^[0-9a-zA-Z_$]+$/; - function isSimpleString(s) { - if (!isString(s)) throw "Non-string argument to isSimpleString: " + s; - return s.length < 50 && execRegExp(simpleStringRegExp, s) !== null; + // Helper function to determine if a string is short. + function isShortString(s) { + if (!isString(s)) throw "Non-string argument to isShortString: " + s; + return s.length < 50; } // Helper function to determine if a string is numeric and its numeric value representable as an integer. @@ -297,8 +295,8 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // TODO should we allow negative indices here as well? if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { push(allOwnElements, index); - } else if (isSimpleString(p) && tryAccessProperty(p, o)) { - // Only include properties with "simple" names and only if they can be accessed on the original object without raising an exception. + } else if (isShortString(p) && tryAccessProperty(p, o)) { + // Only include properties with short names and only if they can be accessed on the original object without raising an exception. recordProperty(p); } } @@ -453,7 +451,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return { argument: { index } }; } function SpecialInput(name) { - if (!isString(name) || !isSimpleString(name)) throw "SpecialInput name is not a (simple) string: " + name; + if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; return { special: { name } }; } function IntInput(value) { @@ -470,7 +468,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return { bigint: { value: bigintToString(value) } }; } function StringInput(value) { - if (!isString(value) || !isSimpleString(value)) throw "StringInput value is not a (simple) string: " + value; + if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; return { string: { value } }; } diff --git a/Sources/Fuzzilli/Mutators/ProbingMutator.swift b/Sources/Fuzzilli/Mutators/ProbingMutator.swift index b6dade48e..de3aaba09 100644 --- a/Sources/Fuzzilli/Mutators/ProbingMutator.swift +++ b/Sources/Fuzzilli/Mutators/ProbingMutator.swift @@ -212,7 +212,6 @@ public class ProbingMutator: RuntimeAssistedMutator { switch property { case .regular(let name): - assert(isValidPropertyName(name)) b.setProperty(name, of: obj, to: value) case .element(let index): b.setElement(index, of: obj, to: value) @@ -257,7 +256,6 @@ public class ProbingMutator: RuntimeAssistedMutator { switch property { case .regular(let name): - assert(isValidPropertyName(name)) b.configureProperty(name, of: obj, usingFlags: PropertyFlags.random(), as: config) case .element(let index): b.configureElement(index, of: obj, usingFlags: PropertyFlags.random(), as: config) @@ -312,11 +310,6 @@ public class ProbingMutator: RuntimeAssistedMutator { } } - private func isValidPropertyName(_ name: String) -> Bool { - // Currently only property names containing whitespaces or newlines are invalid. - return name.rangeOfCharacter(from: .whitespacesAndNewlines) == nil - } - private func parsePropertyName(_ propertyName: String) -> Property? { // Anything that parses as an Int64 is an element index. if let index = Int64(propertyName) { @@ -332,11 +325,6 @@ public class ProbingMutator: RuntimeAssistedMutator { } // Everything else is a regular property name. - guard isValidPropertyName(propertyName) else { - // Invalid property names should have been filtered out on the JavaScript side, so receiving them here is an error. - logger.error("Received invalid property name: \(propertyName)") - return nil - } return .regular(propertyName) } diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 8eddca120..dcd757c54 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -1476,34 +1476,14 @@ public struct Compiler_Protobuf_ObjectProperty: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectProperty.OneOf_Key? = nil - - /// A "regular" property. - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - /// An element. - public var index: Int64 { - get { - if case .index(let v)? = key {return v} - return 0 - } - set {key = .index(newValue)} - } - - /// A computed property. - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var value: Compiler_Protobuf_Expression { get {_value ?? Compiler_Protobuf_Expression()} @@ -1516,18 +1496,9 @@ public struct Compiler_Protobuf_ObjectProperty: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - /// A "regular" property. - case name(String) - /// An element. - case index(Int64) - /// A computed property. - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _value: Compiler_Protobuf_Expression? = nil } @@ -1536,23 +1507,14 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectMethod.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var type: Compiler_Protobuf_FunctionType = .plain @@ -1569,14 +1531,9 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } @@ -1585,35 +1542,22 @@ public struct Compiler_Protobuf_ObjectGetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectGetter.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var body: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil } public struct Compiler_Protobuf_ObjectSetter: Sendable { @@ -1621,23 +1565,14 @@ public struct Compiler_Protobuf_ObjectSetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectSetter.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var parameter: Compiler_Protobuf_Parameter { get {_parameter ?? Compiler_Protobuf_Parameter()} @@ -1652,14 +1587,9 @@ public struct Compiler_Protobuf_ObjectSetter: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil } @@ -5374,7 +5304,7 @@ extension Compiler_Protobuf_AssignmentExpression: SwiftProtobuf.Message, SwiftPr extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}index\0\u{1}expression\0\u{1}value\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}value\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5382,36 +5312,8 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Int64? - try decoder.decodeSingularInt64Field(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .index(v) - } - }() - case 3: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 4: try { try decoder.decodeSingularMessageField(value: &self._value) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._value) }() default: break } } @@ -5422,29 +5324,17 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .index?: try { - guard case .index(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularInt64Field(value: v, fieldNumber: 2) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() try { if let v = self._value { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectProperty, rhs: Compiler_Protobuf_ObjectProperty) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs._value != rhs._value {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5453,7 +5343,7 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}type\0\u{1}parameters\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}type\0\u{1}parameters\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5461,30 +5351,10 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeSingularEnumField(value: &self.type) }() - case 4: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - case 5: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self.type) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5495,31 +5365,23 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.type != .plain { - try visitor.visitSingularEnumField(value: self.type, fieldNumber: 3) + try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) } try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 5) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectMethod, rhs: Compiler_Protobuf_ObjectMethod) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs.type != rhs.type {return false} if lhs._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} @@ -5530,7 +5392,7 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5538,28 +5400,8 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5570,25 +5412,17 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 3) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectGetter, rhs: Compiler_Protobuf_ObjectGetter) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5597,7 +5431,7 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}parameter\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}parameter\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5605,29 +5439,9 @@ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() - case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() + case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5638,28 +5452,20 @@ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() try { if let v = self._parameter { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 3) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectSetter, rhs: Compiler_Protobuf_ObjectSetter) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs._parameter != rhs._parameter {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index a3e0bffed..3b4831f1d 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -318,42 +318,26 @@ message AssignmentExpression { } message ObjectProperty { - oneof key { - // A "regular" property. - string name = 1; - // An element. - int64 index = 2; - // A computed property. - Expression expression = 3; - } - Expression value = 4; + PropertyKey key = 1; + Expression value = 2; } message ObjectMethod { - oneof key { - string name = 1; - Expression expression = 2; - } - FunctionType type = 3; - Parameters parameters = 4; - repeated Statement body = 5; + PropertyKey key = 1; + FunctionType type = 2; + Parameters parameters = 3; + repeated Statement body = 4; } message ObjectGetter { - oneof key { - string name = 1; - Expression expression = 2; - } - repeated Statement body = 3; + PropertyKey key = 1; + repeated Statement body = 2; } message ObjectSetter { - oneof key { - string name = 1; - Expression expression = 2; - } - Parameter parameter = 3; - repeated Statement body = 4; + PropertyKey key = 1; + Parameter parameter = 2; + repeated Statement body = 3; } message ObjectField { diff --git a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 264ade1c9..99a5feaf9 100644 --- a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js +++ b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js @@ -8,6 +8,18 @@ console.log("Computed object property"); console.log(obj.theAnswerIs); })(); +console.log("Indexed object property"); +(() => { + const obj = { 67 : 42 }; + console.log(obj[67]); +})(); + +console.log("String literal object property"); +(() => { + const obj = { "?" : 42 }; + console.log(obj["?"]); +})(); + console.log("Computed object method"); (() => { const p = 'theAnswerIs'; @@ -27,6 +39,67 @@ console.log("String literal object method"); console.log(obj["?"]()); })(); +/* +console.log("Computed object property (getter/setter)"); +(() => { + const p = 'theAnswerIs'; + const name = "foo"; + const obj = { + answer: 7, + get [name]() { + console.log("Heavy calculations"); + return this.answer; + }, + set [name](answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj.foo); + obj.foo = 42; + console.log(obj.foo); +})(); +*/ + +console.log("Indexed object property (getter/setter)"); +(() => { + const obj = { + answer: 7, + get 67() { + console.log("Heavy calculations"); + return this.answer; + }, + set 67(answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj[67]); + obj[67] = 42; + console.log(obj[67]); +})(); + +console.log("String literal object property (getter/setter)"); +(() => { + const obj = { + answer: 7, + get "?"() { + console.log("Heavy calculations"); + return this.answer; + }, + set "?"(answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj["?"]); + obj["?"] = 42; + console.log(obj["?"]); +})(); + console.log("Computed class property (field)"); (() => { function classify (name) { diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 8f3b5e6fc..872a4b047 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -583,8 +583,10 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() + let v = b.loadInt(42) b.buildObjectLiteral { obj in for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + obj.addProperty(name, as: v) obj.addMethod(name, with: .parameters(n: 0)) { args in } } @@ -594,21 +596,29 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v8 = { + const v9 = { + "???": 42, "???"() { }, + 0: 42, 0() { }, + "01": 42, "01"() { }, + 1: 42, 1() { }, + "0.1": 42, "0.1"() { }, + "-1": 42, "-1"() { }, + $valid_id_42: 42, $valid_id_42() { }, + "42_invalid_id": 42, "42_invalid_id"() { }, }; @@ -861,8 +871,11 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() + let v = b.loadInt(42) b.buildClassDefinition() { cls in for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + cls.addInstanceProperty(name, value: v) + cls.addStaticProperty(name, value: v) cls.addInstanceMethod(name, with: .parameters(n: 0)) { params in } cls.addStaticMethod(name, with: .parameters(n: 0)) { params in @@ -874,35 +887,51 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { + class C1 { + "???" = 42; + static "???" = 42; "???"() { } static "???"() { } + 0 = 42; + static 0 = 42; 0() { } static 0() { } + "01" = 42; + static "01" = 42; "01"() { } static "01"() { } + 1 = 42; + static 1 = 42; 1() { } static 1() { } + "0.1" = 42; + static "0.1" = 42; "0.1"() { } static "0.1"() { } + "-1" = 42; + static "-1" = 42; "-1"() { } static "-1"() { } + $valid_id_42 = 42; + static $valid_id_42 = 42; $valid_id_42() { } static $valid_id_42() { } + "42_invalid_id" = 42; + static "42_invalid_id" = 42; "42_invalid_id"() { } static "42_invalid_id"() { @@ -1960,7 +1989,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj) } @@ -1969,14 +1998,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Funky["???"](); - Funky[0](); - Funky["01"](); - Funky[1](); - Funky["0.1"](); - Funky["-1"](); - Funky.$valid_id_42(); - Funky["42_invalid_id"](); + const v0 = {}; + v0["???"](); + v0[0](); + v0["01"](); + v0[1](); + v0["0.1"](); + v0["-1"](); + v0.$valid_id_42(); + v0["42_invalid_id"](); """ @@ -1987,7 +2017,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) let values = b.createArray(with: []) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj, withArgs: [values], spreading: [true]) @@ -1997,15 +2027,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ + const v0 = {}; const v1 = []; - Funky["???"](...v1); - Funky[0](...v1); - Funky["01"](...v1); - Funky[1](...v1); - Funky["0.1"](...v1); - Funky["-1"](...v1); - Funky.$valid_id_42(...v1); - Funky["42_invalid_id"](...v1); + v0["???"](...v1); + v0[0](...v1); + v0["01"](...v1); + v0[1](...v1); + v0["0.1"](...v1); + v0["-1"](...v1); + v0.$valid_id_42(...v1); + v0["42_invalid_id"](...v1); """ @@ -2016,7 +2047,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { let bound = b.bindMethod(name, on: obj) b.callFunction(bound, withArgs: [obj]) @@ -2026,22 +2057,23 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v1 = Function.prototype.call.bind(Funky["???"]); - v1(Funky); - let v3 = Function.prototype.call.bind(Funky[0]); - v3(Funky); - let v5 = Function.prototype.call.bind(Funky["01"]); - v5(Funky); - let v7 = Function.prototype.call.bind(Funky[1]); - v7(Funky); - let v9 = Function.prototype.call.bind(Funky["0.1"]); - v9(Funky); - let v11 = Function.prototype.call.bind(Funky["-1"]); - v11(Funky); - let v13 = Function.prototype.call.bind(Funky.$valid_id_42); - v13(Funky); - let v15 = Function.prototype.call.bind(Funky["42_invalid_id"]); - v15(Funky); + const v0 = {}; + let v1 = Function.prototype.call.bind(v0["???"]); + v1(v0); + let v3 = Function.prototype.call.bind(v0[0]); + v3(v0); + let v5 = Function.prototype.call.bind(v0["01"]); + v5(v0); + let v7 = Function.prototype.call.bind(v0[1]); + v7(v0); + let v9 = Function.prototype.call.bind(v0["0.1"]); + v9(v0); + let v11 = Function.prototype.call.bind(v0["-1"]); + v11(v0); + let v13 = Function.prototype.call.bind(v0.$valid_id_42); + v13(v0); + let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); + v15(v0); """ @@ -2103,6 +2135,95 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testPropertyLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createObject(with: [:]) + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.setProperty(name, of: obj, to: b.getProperty(name, of: obj)) + b.updateProperty(name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) + b.deleteProperty(name, of: obj) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v0 = {}; + v0["???"] = v0["???"]; + v0["???"] += v0?.["???"]; + delete v0["???"]; + v0[0] = v0[0]; + v0[0] += v0?.[0]; + delete v0[0]; + v0["01"] = v0["01"]; + v0["01"] += v0?.["01"]; + delete v0["01"]; + v0[1] = v0[1]; + v0[1] += v0?.[1]; + delete v0[1]; + v0["0.1"] = v0["0.1"]; + v0["0.1"] += v0?.["0.1"]; + delete v0["0.1"]; + v0["-1"] = v0["-1"]; + v0["-1"] += v0?.["-1"]; + delete v0["-1"]; + v0.$valid_id_42 = v0.$valid_id_42; + v0.$valid_id_42 += v0?.$valid_id_42; + delete v0.$valid_id_42; + v0["42_invalid_id"] = v0["42_invalid_id"]; + v0["42_invalid_id"] += v0?.["42_invalid_id"]; + delete v0["42_invalid_id"]; + + """ + + XCTAssertEqual(actual, expected) + } + + func testSuperPropertyLiftingWeirdNames() { + let fuzzer: Fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildClassDefinition() { cls in + cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.setSuperProperty(name, to: b.getSuperProperty(name)) + b.updateSuperProperty(name, with: b.getSuperProperty(name), using: .Add) + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C0 { + sub() { + super["???"] = super["???"]; + super["???"] += super["???"]; + super[0] = super[0]; + super[0] += super[0]; + super["01"] = super["01"]; + super["01"] += super["01"]; + super[1] = super[1]; + super[1] += super[1]; + super["0.1"] = super["0.1"]; + super["0.1"] += super["0.1"]; + super["-1"] = super["-1"]; + super["-1"] += super["-1"]; + super.$valid_id_42 = super.$valid_id_42; + super.$valid_id_42 += super.$valid_id_42; + super["42_invalid_id"] = super["42_invalid_id"]; + super["42_invalid_id"] += super["42_invalid_id"]; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + func testConstructLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() From 43fa1745355b22d641f1018ba87a0e1020c5464c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Mar 2026 14:37:14 +0100 Subject: [PATCH 011/223] [js] Also generate empty strings Bug: 495679730 Change-Id: I45c1af939f3e1a81fc1c3a2649652e25c644cc82 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9137477 Reviewed-by: Darius Mercadier Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 ++++- Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index aa1127564..7160b7c71 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -377,7 +377,10 @@ public class ProgramBuilder { }, { String(self.randomInt()) }, { - String.random(ofLength: Int.random(in: 1...5)) + // Prefer smaller strings both for readability as well as for small string optimizations + // (e.g. optimizations for single character strings) but also generate larger strings + // to hit cons string ("rope" / concatenated string) cases. + String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) }) } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9461bd760..c13a808a5 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -59,7 +59,7 @@ public class JavaScriptEnvironment: ComponentBase { public let interestingFloats = [-Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan] // TODO more? - public let interestingStrings = jsTypeNames + public let interestingStrings = jsTypeNames + [""] // Copied from // https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/dicts/regexp.dict From e0f0b0b20eccce3be81a37b492c4c0721bbb8ad4 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 27 Mar 2026 11:11:23 +0000 Subject: [PATCH 012/223] Try minimizing crashes of instrumented runs When a program instrumented by RuntimeAssistedMutator crashes, we avoid calling processCrash() on it immediately. This is because the boilerplate code added during instrumentation makes such crashes difficult to minimize (see, e.g., https://g-issues.chromium.org/issues/488963988?pli=1&authuser=0). Instead, we follow this procedure: 1. Always log the crash of the instrumented program. 2. Check if the process()'d version of the instrumented program also crashes. 3. If yes, we call processCrash() on that program instead, as its more straightforward to minimize. Bug: 488963988 Change-Id: Iffefc9435f4ef31a3fbf798d374a04f9f1fc115a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9129498 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Fuzzer.swift | 35 +++++--- .../Mutators/RuntimeAssistedMutator.swift | 34 +++++++- .../CrashingInstrumentationMutator.swift | 55 +++++++++++++ .../RuntimeAssistedMutatorTests.swift | 82 +++++++++++++++++++ 4 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 Tests/FuzzilliTests/CrashingInstrumentationMutator.swift create mode 100644 Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index f7ef762d7..787db836c 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -789,25 +789,34 @@ public class Fuzzer { return true } + /// Collect information about a crash. + func collectCrashInfo(for program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, withExectime exectime: TimeInterval) -> [String] { + var info = [String]() + info.append("CRASH INFO") + info.append("==========") + if let tag = config.tag { + info.append("INSTANCE TAG: \(tag)") + } + info.append("TERMSIG: \(termsig)") + info.append("STDERR:") + info.append(stderr.trimmingCharacters(in: .newlines)) + info.append("STDOUT:") + info.append(stdout.trimmingCharacters(in: .newlines)) + info.append("FUZZER ARGS: \(config.arguments.joined(separator: " "))") + info.append("TARGET ARGS: \(runner.processArguments.joined(separator: " "))") + info.append("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") + info.append("EXECUTION TIME: \(Int(exectime * 1000))ms") + return info + } + /// Process a program that causes a crash. func processCrash(_ program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval) { func processCommon(_ program: Program) { let hasCrashInfo = program.comments.at(.footer)?.contains("CRASH INFO") ?? false if !hasCrashInfo { - program.comments.add("CRASH INFO", at: .footer) - program.comments.add("==========", at: .footer) - if let tag = config.tag { - program.comments.add("INSTANCE TAG: \(tag)", at: .footer) + for line in collectCrashInfo(for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, withExectime: exectime) { + program.comments.add(line, at: .footer) } - program.comments.add("TERMSIG: \(termsig)", at: .footer) - program.comments.add("STDERR:", at: .footer) - program.comments.add(stderr.trimmingCharacters(in: .newlines), at: .footer) - program.comments.add("STDOUT:", at: .footer) - program.comments.add(stdout.trimmingCharacters(in: .newlines), at: .footer) - program.comments.add("FUZZER ARGS: \(config.arguments.joined(separator: " "))", at: .footer) - program.comments.add("TARGET ARGS: \(runner.processArguments.joined(separator: " "))", at: .footer) - program.comments.add("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))", at: .footer) - program.comments.add("EXECUTION TIME: \(Int(exectime * 1000))ms", at: .footer) } assert(program.comments.at(.footer)?.contains("CRASH INFO") ?? false) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index baad473fa..385d663a3 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -32,6 +32,7 @@ public class RuntimeAssistedMutator: Mutator { enum Outcome: String, CaseIterable { case success = "Success" case cannotInstrument = "Cannot instrument input" + case instrumentedProgramCrashed = "Instrumented program crashed" case instrumentedProgramFailed = "Instrumented program failed" case instrumentedProgramTimedOut = "Instrumented program timed out" case noResults = "No results received" @@ -90,6 +91,10 @@ public class RuntimeAssistedMutator: Mutator { // Execute the instrumented program (with a higher timeout) and collect the output. let execution = fuzzer.execute(instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, purpose: .runtimeAssistedMutation) + // We need to cache these because they're invalidated the next time we call execute(). + let oldStdout = execution.stdout + let oldStderr = execution.stderr + let oldFuzzout = execution.fuzzout switch execution.outcome { case .failed(_): // We generally do not expect the instrumentation code itself to cause runtime exceptions. Even if it performs new actions those should be guarded with try-catch. @@ -109,8 +114,31 @@ public class RuntimeAssistedMutator: Mutator { // In this case we still try to process the instrumentation output (if any) and produce the final, uninstrumented program // so that we obtain reliable testcase for crashes due to (1). However, to not loose crashes due to (2), we also // report the instrumented program as crashing here. We may therefore end up with two crashes from one mutation. - let stdout = execution.fuzzout + "\n" + execution.stdout - fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + + let stdout = oldFuzzout + "\n" + oldStdout + + // We log the crash here in case something goes wrong. + let crashInfoText = fuzzer.collectCrashInfo(for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, withExectime: execution.execTime) + logger.error("Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))") + + // Check if the process()'d program also crashes. If yes, we report that crash instead. + // This allows to use Fuzzilli's input minimization, which wouldn't work for the instrumented program. + let (mutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + if let mutatedProgram { + assert(outcome == .success) + + let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) + if case .crashed(let signal) = execution.outcome { + logger.info("Mutated program crashed as well, reporting mutated program instead") + let stdout = execution.fuzzout + "\n" + execution.stdout + fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + return failure(.instrumentedProgramCrashed) + } + } + + // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. + logger.info("Mutated program did not crash, reporting original crash of the instrumented program") + fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. break @@ -119,7 +147,7 @@ public class RuntimeAssistedMutator: Mutator { } // Process the output to build the mutated program. - let (maybeMutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (maybeMutatedProgram, outcome) = process(oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) guard let mutatedProgram = maybeMutatedProgram else { assert(outcome != .success) return failure(outcome) diff --git a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift new file mode 100644 index 000000000..5863b6c18 --- /dev/null +++ b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift @@ -0,0 +1,55 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation +@testable import Fuzzilli + +// This mutator generates a crashing instrumented program. +// It is used for testing: the process()'d program should be +// reported instead of the instrument()'d program, if that program +// also crashes, in order to enable better minimization. + +class CrashingInstrumentationMutator: RuntimeAssistedMutator { + private let shouldProcessedProgramCrash: Bool + + init(shouldProcessedProgramCrash: Bool = true) { + self.shouldProcessedProgramCrash = shouldProcessedProgramCrash + super.init("CrashingInstrumentationMutator", verbose: true) + } + + override func instrument(_ program: Program, for fuzzer: Fuzzer) -> Program? { + let b = fuzzer.makeBuilder() + b.eval("fuzzilli('FUZZILLI_CRASH', 0)"); + + // Add a JsInternalOperation to satisfy the assertion in RuntimeAssistedMutator.swift:89 + let v = b.loadInt(42) + b.doPrint(v) + + b.append(program) + return b.finalize() + } + + + override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + // Purpose of this print: Distinguish crashes originating from instrument() and process(). + let printFct = b.createNamedVariable(forBuiltin: "print") + b.callFunction(printFct, withArgs: [b.loadString("This is the processed program")]) + if self.shouldProcessedProgramCrash { + b.append(instrumentedProgram) + } + return (b.finalize(), .success) + } + + override func logAdditionalStatistics() {} +} diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift new file mode 100644 index 000000000..9105c0544 --- /dev/null +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -0,0 +1,82 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import XCTest +@testable import Fuzzilli + +class RuntimeAssistedMutatorTests: XCTestCase { + class CrashMockScriptRunner: ScriptRunner { + var processArguments: [String] = [] + var env: [(String, String)] = [] + func run(_ script: String, withTimeout timeout: UInt32) -> Execution { + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") { + return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + } else { + return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + } + } + func setEnvironmentVariable(_ key: String, to value: String) {} + func initialize(with fuzzer: Fuzzer) {} + var isInitialized: Bool { true } + } + + // This test checks that if *both* the instrumented and the processed programs crash, + // we report the processed program. + + func testInstrumentedAndProcessedProgramsCrash() { + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner) + + let mutator = CrashingInstrumentationMutator() + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on processed program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let lifted = fuzzer.lifter.lift(ev.program) + if lifted.contains("This is the processed program") { + crashEventTriggered.fulfill() + } + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } + + // This test checks that if *only* the instrumented program crashes, we report it. + + func testOnlyInstrumentedProgramCrashes() { + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner) + + let mutator = CrashingInstrumentationMutator(shouldProcessedProgramCrash: false) + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let lifted = fuzzer.lifter.lift(ev.program) + if !lifted.contains("This is the processed program") { + crashEventTriggered.fulfill() + } + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } +} From 6c0c84705105400011225f441808b99db53c614a Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Mon, 30 Mar 2026 08:53:33 +0000 Subject: [PATCH 013/223] Use logger.warning() instead of logger.info() on instrumentation crash We need at least "warning" level to see logs from worker threads. Change-Id: I4ec5d9d89f5697cf5710a250888e054789716f78 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9151416 Commit-Queue: Leon Bettscheider Reviewed-by: Matthias Liedtke Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 385d663a3..6a8b29c08 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -129,7 +129,7 @@ public class RuntimeAssistedMutator: Mutator { let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) if case .crashed(let signal) = execution.outcome { - logger.info("Mutated program crashed as well, reporting mutated program instead") + logger.warning("Mutated program crashed as well, reporting mutated program instead") let stdout = execution.fuzzout + "\n" + execution.stdout fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) return failure(.instrumentedProgramCrashed) @@ -137,7 +137,7 @@ public class RuntimeAssistedMutator: Mutator { } // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. - logger.info("Mutated program did not crash, reporting original crash of the instrumented program") + logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. From 65ed5fb13e3619f12669fc61e36568bbb4b12882 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 26 Mar 2026 11:40:05 +0100 Subject: [PATCH 014/223] Work-around false-positive leak reports for regular expressions Fixed: 496097209 Change-Id: Icb0f88bcf619791fa3a45af7f0f2cd73428d37df Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9141456 Auto-Submit: Michael Achenbach Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index c13a808a5..cb052d76f 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -318,34 +318,30 @@ public class JavaScriptEnvironment: ComponentBase { private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] - private let validIdentifierOrIndex: Regex? - private let validDotNotationName: Regex? - private let validPropertyIndex: Regex? - - public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { + private struct ValidationRegexes { // A simple approximation of a valid JS identifier (used in dot // notation and for property and method names). - let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" + static let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" // A non-negative integer (with no leading zero) for index access // without quotes. - let index = "[1-9]\\d*|0" - - // Initialize regular expressions to determine valid property - // identifiers: + static let index = "[1-9]\\d*|0" // We support simple identifiers and non-negative numbers. Other // names will be quoted. // We don't support unquoted doubles. - self.validIdentifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") + static let identifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") // For dot notation we only support simple identifiers. We don't // support all possible names according to JS spec. // Unsupported names will be accessed with bracket notation. - self.validDotNotationName = try! Regex("^(\(simpleId))$") + static let dotNotationName = try! Regex("^(\(simpleId))$") // Valid indexes to use in bracket notation without quotes. - self.validPropertyIndex = try! Regex("^(\(index))$") + static let propertyIndex = try! Regex("^(\(index))$") + } + + public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { super.init(name: "JavaScriptEnvironment") @@ -1005,15 +1001,15 @@ public class JavaScriptEnvironment: ComponentBase { } func isValidIdentifierOrIndex(_ name: String) -> Bool { - return (try? validIdentifierOrIndex?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.identifierOrIndex.wholeMatch(in: name)) != nil } func isValidDotNotationName(_ name: String) -> Bool { - return (try? validDotNotationName?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.dotNotationName.wholeMatch(in: name)) != nil } func isValidPropertyIndex(_ name: String) -> Bool { - return (try? validPropertyIndex?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.propertyIndex.wholeMatch(in: name)) != nil } } From f74d10a0e358454875f8a2e0450146f965fa674b Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 31 Mar 2026 11:50:47 +0200 Subject: [PATCH 015/223] Remove dropped wasm flag in test This was removed in https://crrev.com/c/7708297 Bug: 42202693 Change-Id: Ia3b8b197b28b62ba6eb73aeda498ae748fb093ee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155336 Auto-Submit: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke Commit-Queue: Michael Achenbach --- Tests/FuzzilliTests/EnvironmentTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index 1c55adf57..7819fa883 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -25,7 +25,7 @@ class EnvironmentTests: XCTestCase { /// Test all the builtin objects that are reachable from the global this. /// (This does not include anything that needs a constructor to be called.) func testJSEnvironmentLive() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--experimental-wasm-rab-integration", "--wasm-test-streaming", "--js-staging"]) + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) let jsProg = buildAndLiftProgram(withLiftingOptions: [.includeComments]) { b in let jsEnvironment = b.fuzzer.environment var seenTypeGroups = Set() From b0b6605a736908245c8a13241f783df1472f790f Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 31 Mar 2026 16:26:57 +0200 Subject: [PATCH 016/223] Enable more getters and setters This enables computed getters and setters for classes and adds the remaining bits to support computed getters and setters for object expressions. Also fully supports and tests getters and setters with non-identifier names for classes. Bug: 446634535 Change-Id: Ib18477c237674b8b9c911f36ba3e53daed136fb8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9100459 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 71 ++++- .../CodeGen/CodeGeneratorWeights.swift | 4 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 164 ++++++----- Sources/Fuzzilli/Compiler/Compiler.swift | 82 ++++-- Sources/Fuzzilli/Compiler/Parser/parser.js | 12 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 32 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 32 +++ Sources/Fuzzilli/FuzzIL/JsOperations.swift | 60 ++++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 8 + Sources/Fuzzilli/FuzzIL/Semantics.swift | 8 + Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 38 +++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 36 ++- .../Fuzzilli/Minimization/BlockReducer.swift | 9 +- .../Minimization/InliningReducer.swift | 14 +- .../Fuzzilli/Mutators/OperationMutator.swift | 8 + Sources/Fuzzilli/Protobuf/ast.pb.swift | 49 +++- Sources/Fuzzilli/Protobuf/ast.proto | 4 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 258 ++++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 26 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 210 +++++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 8 + .../computed_and_indexed_properties.js | 18 -- Tests/FuzzilliTests/LifterTest.swift | 212 +++++++++++++- 23 files changed, 1217 insertions(+), 146 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 7160b7c71..d29c09b88 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -903,6 +903,15 @@ public class ProgramBuilder { return randomVariable(ofType: .jsAnything)! } + /// Tries to find a JavaScript variable that hasn't already been added + /// to the given list. + public func randomJsVariable(notIn variables: [Variable]) -> Variable { + let variable = findVariable { + !variables.contains($0) && type(of: $0).Is(.jsAnything) + } + return variable ?? randomJsVariable() + } + /// Returns up to N (different) random JavaScript variables. /// This method will only return fewer than N variables if the number of currently visible variables is less than N. public func randomJsVariables(upTo n: Int) -> [Variable] { @@ -2529,7 +2538,9 @@ public class ProgramBuilder { public fileprivate(set) var methods: [String] = [] public fileprivate(set) var computedMethods: [Variable] = [] public fileprivate(set) var getters: [String] = [] + public fileprivate(set) var computedGetters: [Variable] = [] public fileprivate(set) var setters: [String] = [] + public fileprivate(set) var computedSetters: [Variable] = [] public fileprivate(set) var hasPrototype = false fileprivate init(in b: ProgramBuilder) { @@ -2577,11 +2588,23 @@ public class ProgramBuilder { b.emit(EndObjectLiteralGetter()) } + public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginObjectLiteralComputedGetter(), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndObjectLiteralComputedGetter()) + } + public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginObjectLiteralSetter(propertyName: name)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralSetter()) } + + public func addComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginObjectLiteralComputedSetter(), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndObjectLiteralComputedSetter()) + } } @discardableResult @@ -2616,7 +2639,9 @@ public class ProgramBuilder { public fileprivate(set) var instanceMethods: [String] = [] public fileprivate(set) var instanceComputedMethods: [Variable] = [] public fileprivate(set) var instanceGetters: [String] = [] + public fileprivate(set) var instanceComputedGetters: [Variable] = [] public fileprivate(set) var instanceSetters: [String] = [] + public fileprivate(set) var instanceComputedSetters: [Variable] = [] public fileprivate(set) var staticProperties: [String] = [] public fileprivate(set) var staticElements: [Int64] = [] @@ -2624,7 +2649,9 @@ public class ProgramBuilder { public fileprivate(set) var staticMethods: [String] = [] public fileprivate(set) var staticComputedMethods: [Variable] = [] public fileprivate(set) var staticGetters: [String] = [] + public fileprivate(set) var staticComputedGetters: [Variable] = [] public fileprivate(set) var staticSetters: [String] = [] + public fileprivate(set) var staticComputedSetters: [Variable] = [] // These sets are required to ensure syntactic correctness, not just as an optimization to // avoid adding duplicate fields: @@ -2688,12 +2715,24 @@ public class ProgramBuilder { b.emit(EndClassGetter()) } + public func addInstanceComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginClassComputedGetter(isStatic: false), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndClassComputedGetter()) + } + public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } + public func addInstanceComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginClassComputedSetter(isStatic: false), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndClassComputedSetter()) + } + public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) @@ -2735,12 +2774,24 @@ public class ProgramBuilder { b.emit(EndClassGetter()) } + public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginClassComputedGetter(isStatic: true), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndClassComputedGetter()) + } + public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } + public func addStaticComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginClassComputedSetter(isStatic: true), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndClassComputedSetter()) + } + public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) @@ -4973,12 +5024,18 @@ public class ProgramBuilder { currentObjectLiteral.computedMethods.append(instr.input(0)) case .beginObjectLiteralGetter(let op): currentObjectLiteral.getters.append(op.propertyName) + case .beginObjectLiteralComputedGetter: + currentObjectLiteral.computedGetters.append(instr.input(0)) case .beginObjectLiteralSetter(let op): currentObjectLiteral.setters.append(op.propertyName) + case .beginObjectLiteralComputedSetter: + currentObjectLiteral.computedSetters.append(instr.input(0)) case .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, - .endObjectLiteralSetter: + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter: break case .endObjectLiteral: activeObjectLiterals.pop() @@ -5023,12 +5080,24 @@ public class ProgramBuilder { } else { activeClassDefinitions.top.instanceGetters.append(op.propertyName) } + case .beginClassComputedGetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedGetters.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedGetters.append(instr.input(0)) + } case .beginClassSetter(let op): if op.isStatic { activeClassDefinitions.top.staticSetters.append(op.propertyName) } else { activeClassDefinitions.top.instanceSetters.append(op.propertyName) } + case .beginClassComputedSetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedSetters.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedSetters.append(instr.input(0)) + } case .classAddPrivateProperty(let op): activeClassDefinitions.top.privateProperties.append(op.propertyName) case .beginClassPrivateMethod(let op): diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index aa026f062..a26982e9c 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -68,6 +68,8 @@ public let codeGeneratorWeights = [ "ObjectLiteralComputedMethodGenerator": 3, "ObjectLiteralGetterGenerator": 3, "ObjectLiteralSetterGenerator": 3, + "ObjectLiteralComputedGetterGenerator": 3, + "ObjectLiteralComputedSetterGenerator": 3, // // // The following generators determine how frequently different // // types of fields are generated in class definitions. @@ -91,6 +93,8 @@ public let codeGeneratorWeights = [ "ClassPrivateInstanceMethodGenerator": 5, "ClassPrivateStaticPropertyGenerator": 5, "ClassPrivateStaticMethodGenerator": 5, + "ClassComputedGetterGenerator": 3, + "ClassComputedSetterGenerator": 3, "ObjectWithSpreadGenerator": 2, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 5a3bed0eb..dfa73e95f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -719,17 +719,8 @@ public let CodeGenerators: [CodeGenerator] = [ inputs: .one ) { b, value in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - if attempts >= 10 { - // Could not find anything. - // Since this CodeGenerator does not produce anything it is fine to bail. - return - } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentObjectLiteral.computedProperties.contains(propertyName) + let propertyName = b.randomJsVariable( + notIn: b.currentObjectLiteral.computedProperties) b.currentObjectLiteral.addComputedProperty(propertyName, as: value) }, @@ -782,19 +773,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method] ) { b in // Try to find a computed method name that hasn't already been added to this literal. - - var methodName: Variable - var attempts = 0 - repeat { - methodName = b.randomJsVariable() - if attempts >= 10 { - // This might lead to having two computed methods with the same name (so one - // will overwrite the other). - break - } - attempts += 1 - } while b.currentObjectLiteral.computedMethods.contains( - methodName) + let methodName = b.randomJsVariable( + notIn: b.currentObjectLiteral.computedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -809,7 +789,6 @@ public let CodeGenerators: [CodeGenerator] = [ ) { b, inp in b.doReturn(inp) b.emit(EndObjectLiteralComputedMethod()) - }, ]), @@ -825,7 +804,6 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentObjectLiteral.properties + b.currentObjectLiteral.getters) b.emit(BeginObjectLiteralGetter(propertyName: propertyName)) - }, GeneratorStub( "ObjectLiteralGetterEndGenerator", @@ -858,6 +836,46 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), + CodeGenerator( + "ObjectLiteralComputedGetterGenerator", + [ + GeneratorStub( + "ObjectLiteralComputedGetterBeginGenerator", + inContext: .single(.objectLiteral), + provides: [.javascript, .subroutine, .method] + ) { b in + let propertyName = b.randomJsVariable(notIn: b.currentObjectLiteral.computedGetters) + b.emit(BeginObjectLiteralComputedGetter(), withInputs: [propertyName]) + }, + GeneratorStub( + "ObjectLiteralComputedGetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method]), + inputs: .one + ) { b, inp in + b.doReturn(inp) + b.emit(EndObjectLiteralComputedGetter()) + }, + ]), + + CodeGenerator( + "ObjectLiteralComputedSetterGenerator", + [ + GeneratorStub( + "ObjectLiteralComputedSetterBeginGenerator", + inContext: .single(.objectLiteral), + provides: [.javascript, .subroutine, .method] + ) { b in + let propertyName = b.randomJsVariable(notIn: b.currentObjectLiteral.computedSetters) + b.emit(BeginObjectLiteralComputedSetter(), withInputs: [propertyName]) + }, + GeneratorStub( + "ObjectLiteralComputedSetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method]) + ) { b in + b.emit(EndObjectLiteralComputedSetter()) + }, + ]), + CodeGenerator( "ClassConstructorGenerator", [ @@ -939,15 +957,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassInstanceComputedPropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - guard attempts < 10 else { return } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.instanceComputedProperties.contains( - propertyName) - + let propertyName = b.randomJsVariable( + notIn: b.currentClassDefinition.instanceComputedProperties) let value = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addInstanceComputedProperty( propertyName, value: value) @@ -991,15 +1002,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a method that hasn't already been added to this class. - var methodName = b.randomJsVariable() - var attempts = 0 - repeat { - guard attempts < 10 else { break } - methodName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.instanceComputedMethods.contains( - methodName) - + let methodName = b.randomJsVariable( + notIn: b.currentClassDefinition.instanceComputedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -1089,18 +1093,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassStaticComputedPropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - guard attempts < 10 else { - // We are in .classDefinition context here and cannot create new JavaScript variables, so just bail here. - return - } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.staticComputedProperties.contains( - propertyName) - + let propertyName = b.randomJsVariable( + notIn: b.currentClassDefinition.staticComputedProperties) let value = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addStaticComputedProperty( propertyName, value: value) @@ -1163,15 +1157,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a method that hasn't already been added to this class. - var methodName = b.randomJsVariable() - var attempts = 0 - repeat { - guard attempts < 10 else { break } - methodName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.staticComputedMethods.contains( - methodName) - + let methodName = b.randomJsVariable( + notIn: b.currentClassDefinition.staticComputedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -1234,6 +1221,53 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), + CodeGenerator( + "ClassComputedGetterGenerator", + [ + GeneratorStub( + "ClassComputedGetterBeginGenerator", + inContext: .single(.classDefinition), + provides: [.javascript, .subroutine, .method, .classMethod] + ) { b in + let isStatic = probability(0.3) + let existing = isStatic + ? b.currentClassDefinition.staticComputedGetters + : b.currentClassDefinition.instanceComputedGetters + let propertyName = b.randomJsVariable(notIn: existing) + b.emit(BeginClassComputedGetter(isStatic: isStatic), withInputs: [propertyName]) + }, + GeneratorStub( + "ClassComputedGetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]) + ) { b in + b.doReturn(b.randomJsVariable()) + b.emit(EndClassComputedGetter()) + }, + ]), + + CodeGenerator( + "ClassComputedSetterGenerator", + [ + GeneratorStub( + "ClassComputedSetterBeginGenerator", + inContext: .single(.classDefinition), + provides: [.javascript, .subroutine, .method, .classMethod] + ) { b in + let isStatic = probability(0.3) + let existing = isStatic + ? b.currentClassDefinition.staticComputedSetters + : b.currentClassDefinition.instanceComputedSetters + let propertyName = b.randomJsVariable(notIn: existing) + b.emit(BeginClassComputedSetter(isStatic: isStatic), withInputs: [propertyName]) + }, + GeneratorStub( + "ClassComputedSetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]) + ) { b in + b.emit(EndClassComputedSetter()) + }, + ]), + CodeGenerator( "ClassPrivateInstancePropertyGenerator", inContext: .single(.classDefinition) ) { b in diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 5a6d5be9e..53ad5ccc4 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -76,18 +76,26 @@ public class JavaScriptCompiler { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in class declaration") } - if case .property(let property) = field { + + let key: Compiler_Protobuf_PropertyKey? + switch field { + case .property(let property): if property.hasValue { propertyValues.append(try compileExpression(property.value)) } - if case .expression(let expression) = property.key.body { - computedKeys.append(try compileExpression(expression)) - } + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key + case .ctor, .staticInitializer: + key = nil } - if case .method(let method) = field { - if case .expression(let expression) = method.key.body { - computedKeys.append(try compileExpression(expression)) - } + + if let key, case .expression(let expression) = key.body { + computedKeys.append(try compileExpression(expression)) } } @@ -179,7 +187,18 @@ public class JavaScriptCompiler { } case .getter(let getter): - let head = emit(BeginClassGetter(propertyName: getter.name, isStatic: getter.isStatic)) + let head: Instruction + guard let key = getter.key.body else { + throw CompilerError.invalidNodeError("Missing key in class getter") + } + switch key { + case .name(let name): + head = emit(BeginClassGetter(propertyName: name, isStatic: getter.isStatic)) + case .index(let index): + head = emit(BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) + case .expression: + head = emit(BeginClassComputedGetter(isStatic: getter.isStatic), withInputs: [computedKeys.removeLast()]) + } try enterNewScope { map("this", to: head.innerOutput) @@ -188,10 +207,26 @@ public class JavaScriptCompiler { } } - emit(EndClassGetter()) + switch key { + case .name, .index: + emit(EndClassGetter()) + case .expression: + emit(EndClassComputedGetter()) + } case .setter(let setter): - let head = emit(BeginClassSetter(propertyName: setter.name, isStatic: setter.isStatic)) + let head: Instruction + guard let key = setter.key.body else { + throw CompilerError.invalidNodeError("Missing key in class setter") + } + switch key { + case .name(let name): + head = emit(BeginClassSetter(propertyName: name, isStatic: setter.isStatic)) + case .index(let index): + head = emit(BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) + case .expression: + head = emit(BeginClassComputedSetter(isStatic: setter.isStatic), withInputs: [computedKeys.removeLast()]) + } try enterNewScope { var parameters = head.innerOutputs @@ -203,7 +238,12 @@ public class JavaScriptCompiler { } } - emit(EndClassSetter()) + switch key { + case .name, .index: + emit(EndClassSetter()) + case .expression: + emit(EndClassComputedSetter()) + } case .staticInitializer(let staticInitializer): let head = emit(BeginClassStaticInitializer()) @@ -855,7 +895,7 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralGetter(propertyName: String(index))) case .expression: - fatalError("Computed getters are not yet supported") + head = emit(BeginObjectLiteralComputedGetter(), withInputs: [computedKeys.removeLast()]) } try enterNewScope { map("this", to: head.innerOutput) @@ -863,7 +903,12 @@ public class JavaScriptCompiler { try compileStatement(statement) } } - emit(EndObjectLiteralGetter()) + switch key { + case .name, .index: + emit(EndObjectLiteralGetter()) + case .expression: + emit(EndObjectLiteralComputedGetter()) + } case .setter(let setter): guard let key = setter.key.body else { throw CompilerError.invalidNodeError("Missing key in object expression setter") @@ -875,7 +920,7 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralSetter(propertyName: String(index))) case .expression: - fatalError("Computed setters are not yet supported") + head = emit(BeginObjectLiteralComputedSetter(), withInputs: [computedKeys.removeLast()]) } try enterNewScope { var parameters = head.innerOutputs @@ -886,7 +931,12 @@ public class JavaScriptCompiler { try compileStatement(statement) } } - emit(EndObjectLiteralSetter()) + switch key { + case .name, .index: + emit(EndObjectLiteralSetter()) + case .expression: + emit(EndObjectLiteralComputedSetter()) + } } } return emit(EndObjectLiteral()).output diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 0e8b24d16..4d5ece183 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -214,26 +214,22 @@ function parse(script, proto) { let key = visitMemberKey(method); field.method = make('ClassMethod', { key, isStatic, parameters, body }); } else if (method.kind === 'get') { - assert(!method.computed, 'Expected method.computed to be false'); - assert(method.key.type === 'Identifier', "Expected method.key.type to be exactly 'Identifier'"); assert(method.params.length === 0, "Expected method.params.length to be exactly 0"); assert(!method.generator && !method.async, "Expected both conditions to hold: !method.generator and !method.async"); assert(method.body.type === 'BlockStatement', "Expected method.body.type to be exactly 'BlockStatement'"); let body = visitBody(method.body); - const name = method.key.name; - field.getter = make('ClassGetter', { name, isStatic, body }); + let key = visitMemberKey(method); + field.getter = make('ClassGetter', { key, isStatic, body }); } else if (method.kind === 'set') { - assert(!method.computed, 'Expected method.computed to be false'); - assert(method.key.type === 'Identifier', "Expected method.key.type to be exactly 'Identifier'"); assert(method.params.length === 1, "Expected method.params.length to be exactly 1"); assert(!method.generator && !method.async, "Expected both conditions to hold: !method.generator and !method.async"); assert(method.body.type === 'BlockStatement', "Expected method.body.type to be exactly 'BlockStatement'"); let parameter = visitParameter(method.params[0]); let body = visitBody(method.body); - const name = method.key.name; - field.setter = make('ClassSetter', { name, isStatic, parameter, body }); + let key = visitMemberKey(method); + field.setter = make('ClassSetter', { key, isStatic, parameter, body }); } else { throw "Unknown method kind: " + method.kind; } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index f6c5c093e..35c78eae3 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -598,10 +598,18 @@ extension Instruction: ProtobufConvertible { $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { $0.propertyName = op.propertyName } case .endObjectLiteralGetter: $0.endObjectLiteralGetter = Fuzzilli_Protobuf_EndObjectLiteralGetter() + case .beginObjectLiteralComputedGetter: + $0.beginObjectLiteralComputedGetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + case .endObjectLiteralComputedGetter: + $0.endObjectLiteralComputedGetter = Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let op): $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { $0.propertyName = op.propertyName } case .endObjectLiteralSetter: $0.endObjectLiteralSetter = Fuzzilli_Protobuf_EndObjectLiteralSetter() + case .beginObjectLiteralComputedSetter: + $0.beginObjectLiteralComputedSetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + case .endObjectLiteralComputedSetter: + $0.endObjectLiteralComputedSetter = Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() case .endObjectLiteral: $0.endObjectLiteral = Fuzzilli_Protobuf_EndObjectLiteral() case .beginClassDefinition(let op): @@ -660,6 +668,10 @@ extension Instruction: ProtobufConvertible { } case .endClassGetter: $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() + case .beginClassComputedGetter(let op): + $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { $0.isStatic = op.isStatic } + case .endClassComputedGetter: + $0.endClassComputedGetter = Fuzzilli_Protobuf_EndClassComputedGetter() case .beginClassSetter(let op): $0.beginClassSetter = Fuzzilli_Protobuf_BeginClassSetter.with { $0.propertyName = op.propertyName @@ -667,6 +679,10 @@ extension Instruction: ProtobufConvertible { } case .endClassSetter: $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() + case .beginClassComputedSetter(let op): + $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { $0.isStatic = op.isStatic } + case .endClassComputedSetter: + $0.endClassComputedSetter = Fuzzilli_Protobuf_EndClassComputedSetter() case .beginClassStaticInitializer: $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() case .endClassStaticInitializer: @@ -1851,10 +1867,18 @@ extension Instruction: ProtobufConvertible { op = BeginObjectLiteralGetter(propertyName: p.propertyName) case .endObjectLiteralGetter: op = EndObjectLiteralGetter() + case .beginObjectLiteralComputedGetter: + op = BeginObjectLiteralComputedGetter() + case .endObjectLiteralComputedGetter: + op = EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let p): op = BeginObjectLiteralSetter(propertyName: p.propertyName) case .endObjectLiteralSetter: op = EndObjectLiteralSetter() + case .beginObjectLiteralComputedSetter: + op = BeginObjectLiteralComputedSetter() + case .endObjectLiteralComputedSetter: + op = EndObjectLiteralComputedSetter() case .endObjectLiteral: op = EndObjectLiteral() case .beginClassDefinition(let p): @@ -1881,10 +1905,18 @@ extension Instruction: ProtobufConvertible { op = BeginClassGetter(propertyName: p.propertyName, isStatic: p.isStatic) case .endClassGetter: op = EndClassGetter() + case .beginClassComputedGetter(let p): + op = BeginClassComputedGetter(isStatic: p.isStatic) + case .endClassComputedGetter: + op = EndClassComputedGetter() case .beginClassSetter(let p): op = BeginClassSetter(propertyName: p.propertyName, isStatic: p.isStatic) case .endClassSetter: op = EndClassSetter() + case .beginClassComputedSetter(let p): + op = BeginClassComputedSetter(isStatic: p.isStatic) + case .endClassComputedSetter: + op = EndClassComputedSetter() case .beginClassStaticInitializer: op = BeginClassStaticInitializer() case .endClassStaticInitializer: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 7741151a6..8b55de0a5 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1285,7 +1285,9 @@ public struct JSTyper: Analyzer { case .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, .beginPlainFunction, .beginArrowFunction, .beginGeneratorFunction, @@ -1297,14 +1299,18 @@ public struct JSTyper: Analyzer { .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, + .beginClassComputedSetter, .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, .endPlainFunction, .endArrowFunction, .endGeneratorFunction, @@ -1316,7 +1322,9 @@ public struct JSTyper: Analyzer { .endClassMethod, .endClassComputedMethod, .endClassGetter, + .endClassComputedGetter, .endClassSetter, + .endClassComputedSetter, .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). @@ -1571,6 +1579,10 @@ public struct JSTyper: Analyzer { assert(instr.numInnerOutputs == 1) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + case .beginObjectLiteralComputedGetter(_): + // The first inner output is the explicit |this| parameter for the constructor + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + case .beginObjectLiteralSetter(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) @@ -1578,6 +1590,11 @@ public struct JSTyper: Analyzer { processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + case .beginObjectLiteralComputedSetter(let op): + // The first inner output is the explicit |this| parameter for the constructor + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .endObjectLiteral: let instanceType = dynamicObjectGroupManager.finalizeObjectLiteral() set(instr.output, instanceType) @@ -1635,6 +1652,13 @@ public struct JSTyper: Analyzer { dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) } + case .beginClassComputedGetter(let op): + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } + case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { @@ -1647,6 +1671,14 @@ public struct JSTyper: Analyzer { assert(instr.numInnerOutputs == 2) processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .beginClassComputedSetter(let op): + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } + processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| if op.isStatic { diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index f47db65d8..2770d45f1 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -596,6 +596,20 @@ final class EndObjectLiteralGetter: EndAnySubroutine { override var opcode: Opcode { .endObjectLiteralGetter(self) } } +final class BeginObjectLiteralComputedGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginObjectLiteralComputedGetter(self) } + + init() { + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + } +} + +final class EndObjectLiteralComputedGetter: EndAnySubroutine { + override var opcode: Opcode { .endObjectLiteralComputedGetter(self) } +} + // A setter, for example `set prop(a5) {` final class BeginObjectLiteralSetter: BeginAnySubroutine { override var opcode: Opcode { .beginObjectLiteralSetter(self) } @@ -613,6 +627,20 @@ final class EndObjectLiteralSetter: EndAnySubroutine { override var opcode: Opcode { .endObjectLiteralSetter(self) } } +final class BeginObjectLiteralComputedSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginObjectLiteralComputedSetter(self) } + + init() { + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + } +} + +final class EndObjectLiteralComputedSetter: EndAnySubroutine { + override var opcode: Opcode { .endObjectLiteralComputedSetter(self) } +} + final class EndObjectLiteral: JsOperation { override var opcode: Opcode { .endObjectLiteral(self) } @@ -793,6 +821,22 @@ final class EndClassGetter: EndAnySubroutine { override var opcode: Opcode { .endClassGetter(self) } } +final class BeginClassComputedGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedGetter(self) } + let isStatic: Bool + + init(isStatic: Bool) { + self.isStatic = isStatic + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + } +} + +final class EndClassComputedGetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedGetter(self) } +} + final class BeginClassSetter: BeginAnySubroutine { override var opcode: Opcode { .beginClassSetter(self) } @@ -811,6 +855,22 @@ final class EndClassSetter: EndAnySubroutine { override var opcode: Opcode { .endClassSetter(self) } } +final class BeginClassComputedSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedSetter(self) } + let isStatic: Bool + + init(isStatic: Bool) { + self.isStatic = isStatic + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + } +} + +final class EndClassComputedSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedSetter(self) } +} + final class BeginClassStaticInitializer: JsOperation { override var opcode: Opcode { .beginClassStaticInitializer(self) } diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 4918d7d14..3a55fc4cb 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -355,4 +355,12 @@ enum Opcode { case wasmRefTest(WasmRefTest) case wasmDefineAdHocModuleSignatureType(WasmDefineAdHocModuleSignatureType) case wasmRefCast(WasmRefCast) + case beginObjectLiteralComputedGetter(BeginObjectLiteralComputedGetter) + case endObjectLiteralComputedGetter(EndObjectLiteralComputedGetter) + case beginObjectLiteralComputedSetter(BeginObjectLiteralComputedSetter) + case endObjectLiteralComputedSetter(EndObjectLiteralComputedSetter) + case beginClassComputedGetter(BeginClassComputedGetter) + case endClassComputedGetter(EndClassComputedGetter) + case beginClassComputedSetter(BeginClassComputedSetter) + case endClassComputedSetter(EndClassComputedSetter) } diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index ab4af0339..567d58756 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -138,8 +138,12 @@ extension Operation { return endOp is EndObjectLiteralComputedMethod case .beginObjectLiteralGetter: return endOp is EndObjectLiteralGetter + case .beginObjectLiteralComputedGetter: + return endOp is EndObjectLiteralComputedGetter case .beginObjectLiteralSetter: return endOp is EndObjectLiteralSetter + case .beginObjectLiteralComputedSetter: + return endOp is EndObjectLiteralComputedSetter case .beginClassDefinition: return endOp is EndClassDefinition case .beginClassConstructor: @@ -150,8 +154,12 @@ extension Operation { return endOp is EndClassComputedMethod case .beginClassGetter: return endOp is EndClassGetter + case .beginClassComputedGetter: + return endOp is EndClassComputedGetter case .beginClassSetter: return endOp is EndClassSetter + case .beginClassComputedSetter: + return endOp is EndClassComputedSetter case .beginClassStaticInitializer: return endOp is EndClassStaticInitializer case .beginClassPrivateMethod: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 7b94c258e..b624f08a4 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -133,6 +133,15 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndObjectLiteralGetter") + case .beginObjectLiteralComputedGetter: + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginObjectLiteralComputedGetter \(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endObjectLiteralComputedGetter: + w.decreaseIndentionLevel() + w.emit("EndObjectLiteralComputedGetter") + case .beginObjectLiteralSetter(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") w.emit("BeginObjectLiteralSetter `\(op.propertyName)` -> \(params)") @@ -142,6 +151,15 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndObjectLiteralSetter") + case .beginObjectLiteralComputedSetter: + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginObjectLiteralComputedSetter \(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endObjectLiteralComputedSetter: + w.decreaseIndentionLevel() + w.emit("EndObjectLiteralComputedSetter") + case .objectLiteralCopyProperties: w.emit("ObjectLiteralCopyProperties \(input(0))") @@ -239,6 +257,26 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassStaticInitializer") + case .beginClassComputedGetter(let op): + let maybeStatic = op.isStatic ? "static " : "" + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassComputedGetter \(maybeStatic)\(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endClassComputedGetter: + w.decreaseIndentionLevel() + w.emit("EndClassComputedGetter") + + case .beginClassComputedSetter(let op): + let maybeStatic = op.isStatic ? "static " : "" + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassComputedSetter \(maybeStatic)\(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endClassComputedSetter: + w.decreaseIndentionLevel() + w.emit("EndClassComputedSetter") + case .classAddPrivateProperty(let op): let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 0fc5d343a..f38081d9f 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -431,6 +431,11 @@ public class JavaScriptLifter: Lifter { currentObjectLiteral.beginMethod("get \(PROPERTY)() {", &w) bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralComputedGetter: + let PROPERTY = input(0) + currentObjectLiteral.beginMethod("get [\(PROPERTY)]() {", &w) + bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") @@ -439,8 +444,17 @@ public class JavaScriptLifter: Lifter { currentObjectLiteral.beginMethod("set \(PROPERTY)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralComputedSetter: + let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") + let PARAMS = liftParameters(Parameters(count: 1), as: vars) + let PROPERTY = input(0) + currentObjectLiteral.beginMethod("set [\(PROPERTY)](\(PARAMS)) {", &w) + bindVariableToThis(instr.innerOutput(0)) + case .endObjectLiteralGetter, - .endObjectLiteralSetter: + .endObjectLiteralSetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralComputedSetter: currentObjectLiteral.endMethod(&w) case .endObjectLiteral: @@ -559,6 +573,13 @@ public class JavaScriptLifter: Lifter { w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) + case .beginClassComputedGetter(let op): + let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)get [\(PROPERTY)]() {") + w.enterNewBlock() + bindVariableToThis(instr.innerOutput(0)) + case .beginClassSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") @@ -569,10 +590,21 @@ public class JavaScriptLifter: Lifter { w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) + case .beginClassComputedSetter(let op): + let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") + let PARAMS = liftParameters(op.parameters, as: vars) + let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)set [\(PROPERTY)](\(PARAMS)) {") + w.enterNewBlock() + bindVariableToThis(instr.innerOutput(0)) + case .endClassMethod, .endClassComputedMethod, .endClassGetter, - .endClassSetter: + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter: w.leaveCurrentBlock() w.emit("}") diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index af5ca9fbc..ddc493bc7 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -29,7 +29,9 @@ struct BlockReducer: Reducer { case .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, - .beginObjectLiteralSetter: + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter: assert(group.numBlocks == 1) reduceFunctionInObjectLiteral(group.block(0), with: helper) @@ -40,9 +42,10 @@ struct BlockReducer: Reducer { .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, - .beginClassStaticInitializer, - .beginClassPrivateMethod: + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 7f6cf85d5..dcb039c1f 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -59,14 +59,17 @@ struct InliningReducer: Reducer { .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, .beginClassConstructor, .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, - .beginClassStaticInitializer, - .beginClassPrivateMethod: + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, .endArrowFunction, @@ -78,14 +81,17 @@ struct InliningReducer: Reducer { .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, .endClassConstructor, .endClassMethod, .endClassComputedMethod, .endClassGetter, + .endClassComputedGetter, .endClassSetter, - .endClassStaticInitializer, - .endClassPrivateMethod: + .endClassComputedSetter, + .endClassStaticInitializer, .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index d87ef0d23..4d7903629 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -527,13 +527,21 @@ public class OperationMutator: BaseInstructionMutator { .beginObjectLiteralComputedMethod(_), .endObjectLiteralComputedMethod(_), .endObjectLiteralGetter(_), + .beginObjectLiteralComputedGetter(_), + .endObjectLiteralComputedGetter(_), .endObjectLiteralSetter(_), + .beginObjectLiteralComputedSetter(_), + .endObjectLiteralComputedSetter(_), .endObjectLiteral(_), .beginClassDefinition(_), .beginClassConstructor(_), .endClassConstructor(_), .beginClassComputedMethod(_), .endClassComputedMethod(_), + .beginClassComputedGetter(_), + .endClassComputedGetter(_), + .beginClassComputedSetter(_), + .endClassComputedSetter(_), .endClassMethod(_), .endClassGetter(_), .endClassSetter(_), diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index dcd757c54..c556a80e6 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -439,7 +439,14 @@ public struct Compiler_Protobuf_ClassGetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} + } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var isStatic: Bool = false @@ -448,6 +455,8 @@ public struct Compiler_Protobuf_ClassGetter: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil } public struct Compiler_Protobuf_ClassSetter: Sendable { @@ -455,7 +464,14 @@ public struct Compiler_Protobuf_ClassSetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} + } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var isStatic: Bool = false @@ -474,6 +490,7 @@ public struct Compiler_Protobuf_ClassSetter: Sendable { public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil } @@ -3000,7 +3017,7 @@ extension Compiler_Protobuf_ClassMethod: SwiftProtobuf.Message, SwiftProtobuf._M extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ClassGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}isStatic\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}isStatic\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3008,7 +3025,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break @@ -3017,9 +3034,13 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M } public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.isStatic != false { try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) } @@ -3030,7 +3051,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M } public static func ==(lhs: Compiler_Protobuf_ClassGetter, rhs: Compiler_Protobuf_ClassGetter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._key != rhs._key {return false} if lhs.isStatic != rhs.isStatic {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} @@ -3040,7 +3061,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ClassSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}isStatic\0\u{1}parameter\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}isStatic\0\u{1}parameter\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3048,7 +3069,7 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() case 3: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() @@ -3062,9 +3083,9 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.isStatic != false { try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) } @@ -3078,7 +3099,7 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M } public static func ==(lhs: Compiler_Protobuf_ClassSetter, rhs: Compiler_Protobuf_ClassSetter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._key != rhs._key {return false} if lhs.isStatic != rhs.isStatic {return false} if lhs._parameter != rhs._parameter {return false} if lhs.body != rhs.body {return false} diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index 3b4831f1d..d53216273 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -109,13 +109,13 @@ message ClassMethod { } message ClassGetter { - string name = 1; + PropertyKey key = 1; bool isStatic = 2; repeated Statement body = 3; } message ClassSetter { - string name = 1; + PropertyKey key = 1; bool isStatic = 2; Parameter parameter = 3; repeated Statement body = 4; diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 90e194e63..03dc972b5 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1906,6 +1906,26 @@ public struct Fuzzilli_Protobuf_EndObjectLiteralGetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndObjectLiteralComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginObjectLiteralSetter: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -1928,6 +1948,26 @@ public struct Fuzzilli_Protobuf_EndObjectLiteralSetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndObjectLiteralComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_EndObjectLiteral: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -2121,6 +2161,28 @@ public struct Fuzzilli_Protobuf_EndClassGetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginClassComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var isStatic: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndClassComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginClassSetter: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -2145,6 +2207,28 @@ public struct Fuzzilli_Protobuf_EndClassSetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginClassComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var isStatic: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndClassComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginClassStaticInitializer: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -6654,6 +6738,44 @@ extension Fuzzilli_Protobuf_EndObjectLiteralGetter: SwiftProtobuf.Message, Swift } } +extension Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter, rhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndObjectLiteralComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteralComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter, rhs: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginObjectLiteralSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") @@ -6703,6 +6825,44 @@ extension Fuzzilli_Protobuf_EndObjectLiteralSetter: SwiftProtobuf.Message, Swift } } +extension Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter, rhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndObjectLiteralComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteralComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter, rhs: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_EndObjectLiteral: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteral" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -7100,6 +7260,55 @@ extension Fuzzilli_Protobuf_EndClassGetter: SwiftProtobuf.Message, SwiftProtobuf } } +extension Fuzzilli_Protobuf_BeginClassComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}is_static\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedGetter, rhs: Fuzzilli_Protobuf_BeginClassComputedGetter) -> Bool { + if lhs.isStatic != rhs.isStatic {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedGetter, rhs: Fuzzilli_Protobuf_EndClassComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginClassSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") @@ -7154,6 +7363,55 @@ extension Fuzzilli_Protobuf_EndClassSetter: SwiftProtobuf.Message, SwiftProtobuf } } +extension Fuzzilli_Protobuf_BeginClassComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}is_static\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedSetter, rhs: Fuzzilli_Protobuf_BeginClassComputedSetter) -> Bool { + if lhs.isStatic != rhs.isStatic {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedSetter, rhs: Fuzzilli_Protobuf_EndClassComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 4699a27f0..9cfb20633 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -107,6 +107,12 @@ message BeginObjectLiteralGetter { message EndObjectLiteralGetter { } +message BeginObjectLiteralComputedGetter { +} + +message EndObjectLiteralComputedGetter { +} + message BeginObjectLiteralSetter { string propertyName = 1; } @@ -114,6 +120,12 @@ message BeginObjectLiteralSetter { message EndObjectLiteralSetter { } +message BeginObjectLiteralComputedSetter { +} + +message EndObjectLiteralComputedSetter { +} + message EndObjectLiteral { } @@ -171,6 +183,13 @@ message BeginClassGetter { message EndClassGetter { } +message BeginClassComputedGetter { + bool is_static = 1; +} + +message EndClassComputedGetter { +} + message BeginClassSetter { string propertyName = 1; bool is_static = 2; @@ -179,6 +198,13 @@ message BeginClassSetter { message EndClassSetter { } +message BeginClassComputedSetter { + bool is_static = 1; +} + +message EndClassComputedSetter { +} + message BeginClassStaticInitializer { } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 9684e4e6c..a610786ae 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2657,6 +2657,70 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .wasmRefCast(newValue)} } + public var beginObjectLiteralComputedGetter: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter { + get { + if case .beginObjectLiteralComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + } + set {operation = .beginObjectLiteralComputedGetter(newValue)} + } + + public var endObjectLiteralComputedGetter: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter { + get { + if case .endObjectLiteralComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() + } + set {operation = .endObjectLiteralComputedGetter(newValue)} + } + + public var beginObjectLiteralComputedSetter: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter { + get { + if case .beginObjectLiteralComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + } + set {operation = .beginObjectLiteralComputedSetter(newValue)} + } + + public var endObjectLiteralComputedSetter: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter { + get { + if case .endObjectLiteralComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() + } + set {operation = .endObjectLiteralComputedSetter(newValue)} + } + + public var beginClassComputedGetter: Fuzzilli_Protobuf_BeginClassComputedGetter { + get { + if case .beginClassComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedGetter() + } + set {operation = .beginClassComputedGetter(newValue)} + } + + public var endClassComputedGetter: Fuzzilli_Protobuf_EndClassComputedGetter { + get { + if case .endClassComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedGetter() + } + set {operation = .endClassComputedGetter(newValue)} + } + + public var beginClassComputedSetter: Fuzzilli_Protobuf_BeginClassComputedSetter { + get { + if case .beginClassComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedSetter() + } + set {operation = .beginClassComputedSetter(newValue)} + } + + public var endClassComputedSetter: Fuzzilli_Protobuf_EndClassComputedSetter { + get { + if case .endClassComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedSetter() + } + set {operation = .endClassComputedSetter(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -2986,6 +3050,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmRefTest(Fuzzilli_Protobuf_WasmRefTest) case wasmDefineAdHocModuleSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType) case wasmRefCast(Fuzzilli_Protobuf_WasmRefCast) + case beginObjectLiteralComputedGetter(Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter) + case endObjectLiteralComputedGetter(Fuzzilli_Protobuf_EndObjectLiteralComputedGetter) + case beginObjectLiteralComputedSetter(Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter) + case endObjectLiteralComputedSetter(Fuzzilli_Protobuf_EndObjectLiteralComputedSetter) + case beginClassComputedGetter(Fuzzilli_Protobuf_BeginClassComputedGetter) + case endClassComputedGetter(Fuzzilli_Protobuf_EndClassComputedGetter) + case beginClassComputedSetter(Fuzzilli_Protobuf_BeginClassComputedSetter) + case endClassComputedSetter(Fuzzilli_Protobuf_EndClassComputedSetter) } @@ -3034,7 +3106,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7276,6 +7348,110 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefCast(v) } }() + case 328: try { + var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginObjectLiteralComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginObjectLiteralComputedGetter(v) + } + }() + case 329: try { + var v: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endObjectLiteralComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endObjectLiteralComputedGetter(v) + } + }() + case 330: try { + var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginObjectLiteralComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginObjectLiteralComputedSetter(v) + } + }() + case 331: try { + var v: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endObjectLiteralComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endObjectLiteralComputedSetter(v) + } + }() + case 332: try { + var v: Fuzzilli_Protobuf_BeginClassComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginClassComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginClassComputedGetter(v) + } + }() + case 333: try { + var v: Fuzzilli_Protobuf_EndClassComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endClassComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endClassComputedGetter(v) + } + }() + case 334: try { + var v: Fuzzilli_Protobuf_BeginClassComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginClassComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginClassComputedSetter(v) + } + }() + case 335: try { + var v: Fuzzilli_Protobuf_EndClassComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endClassComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endClassComputedSetter(v) + } + }() default: break } } @@ -8594,6 +8770,38 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmRefCast(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 327) }() + case .beginObjectLiteralComputedGetter?: try { + guard case .beginObjectLiteralComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 328) + }() + case .endObjectLiteralComputedGetter?: try { + guard case .endObjectLiteralComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 329) + }() + case .beginObjectLiteralComputedSetter?: try { + guard case .beginObjectLiteralComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 330) + }() + case .endObjectLiteralComputedSetter?: try { + guard case .endObjectLiteralComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 331) + }() + case .beginClassComputedGetter?: try { + guard case .beginClassComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 332) + }() + case .endClassComputedGetter?: try { + guard case .endClassComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 333) + }() + case .beginClassComputedSetter?: try { + guard case .beginClassComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 334) + }() + case .endClassComputedSetter?: try { + guard case .endClassComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 335) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index abf2a678c..bdea24d6c 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -351,6 +351,14 @@ message Instruction { WasmRefTest wasmRefTest = 325; WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 326; WasmRefCast wasmRefCast = 327; + BeginObjectLiteralComputedGetter beginObjectLiteralComputedGetter = 328; + EndObjectLiteralComputedGetter endObjectLiteralComputedGetter = 329; + BeginObjectLiteralComputedSetter beginObjectLiteralComputedSetter = 330; + EndObjectLiteralComputedSetter endObjectLiteralComputedSetter = 331; + BeginClassComputedGetter beginClassComputedGetter = 332; + EndClassComputedGetter endClassComputedGetter = 333; + BeginClassComputedSetter beginClassComputedSetter = 334; + EndClassComputedSetter endClassComputedSetter = 335; } } diff --git a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 99a5feaf9..3289a3180 100644 --- a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js +++ b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js @@ -39,7 +39,6 @@ console.log("String literal object method"); console.log(obj["?"]()); })(); -/* console.log("Computed object property (getter/setter)"); (() => { const p = 'theAnswerIs'; @@ -60,7 +59,6 @@ console.log("Computed object property (getter/setter)"); obj.foo = 42; console.log(obj.foo); })(); -*/ console.log("Indexed object property (getter/setter)"); (() => { @@ -122,7 +120,6 @@ console.log("Computed static class property (field)"); console.log((classify("theAnswerIs")).theAnswerIs); })(); -/* console.log("Computed class property (getter/setter)"); (() => { function classify (name) { @@ -147,9 +144,7 @@ console.log("Computed class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ -/* console.log("Computed static class property (getter/setter)"); (() => { function classify (name) { @@ -174,7 +169,6 @@ console.log("Computed static class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ console.log("Computed class property (method)"); (() => { @@ -244,7 +238,6 @@ console.log("Indexed static class property (method)"); console.log(C[42]()); })(); -/* console.log("Indexed class property (getter/setter)"); (() => { class C { @@ -266,9 +259,7 @@ console.log("Indexed class property (getter/setter)"); c[42] = 42; console.log(c[42]); })(); -*/ -/* console.log("Indexed static class property (getter/setter)"); (() => { class C { @@ -289,7 +280,6 @@ console.log("Indexed static class property (getter/setter)"); C[42] = 42; console.log(C[42]); })(); -*/ console.log("String-indexed class property (field)"); (() => { @@ -331,7 +321,6 @@ console.log("String-indexed static class property (method)"); console.log(C["42"]()); })(); -/* console.log("String-indexed class property (getter/setter)"); (() => { class C { @@ -355,9 +344,7 @@ console.log("String-indexed class property (getter/setter)"); c["42"] = 42; console.log(c["42"]); })(); -*/ -/* console.log("String-indexed static class property (getter/setter)"); (() => { class C { @@ -378,7 +365,6 @@ console.log("String-indexed static class property (getter/setter)"); C["42"] = 42; console.log(C["42"]); })(); -*/ console.log("String-literal class property (field)"); (() => { @@ -420,7 +406,6 @@ console.log("String-literal static class property (method)"); console.log(C["theAnswerIs?"]()); })(); -/* console.log("String-literal class property (getter/setter)"); (() => { class C { @@ -442,9 +427,7 @@ console.log("String-literal class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ -/* console.log("String-literal static class property (getter/setter)"); (() => { class C { @@ -465,4 +448,3 @@ console.log("String-literal static class property (getter/setter)"); C.theAnswerIs = 42; console.log(C.theAnswerIs); })(); -*/ diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 872a4b047..9308fa71a 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -542,6 +542,12 @@ class LifterTests: XCTestCase { obj.addSetter(for: "prop") { this, v in b.setProperty("p", of: this, to: v) } + obj.addComputedGetter(for: v3) { this in + b.doReturn(v1) + } + obj.addComputedSetter(for: v3) { this, v in + b.setProperty("p", of: this, to: v) + } obj.copyProperties(from: otherObject) } @@ -551,7 +557,7 @@ class LifterTests: XCTestCase { let expected = """ const v4 = "foobar" + 42; const v7 = Symbol.toPrimitive; - const v17 = { + const v20 = { p1: 42, __proto__: null, 0: 13.37, @@ -572,6 +578,12 @@ class LifterTests: XCTestCase { set prop(a16) { this.p = a16; }, + get ["foobar"]() { + return 42; + }, + set ["foobar"](a19) { + this.p = a19; + }, ...SomeObject, }; @@ -627,6 +639,69 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testObjectLiteralGetterSetterLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v = b.loadInt(42) + b.buildObjectLiteral { obj in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + obj.addGetter(for: name) { _ in b.doReturn(v) } + obj.addSetter(for: name) { _, _ in } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v25 = { + get "???"() { + return 42; + }, + set "???"(a3) { + }, + get 0() { + return 42; + }, + set 0(a6) { + }, + get "01"() { + return 42; + }, + set "01"(a9) { + }, + get 1() { + return 42; + }, + set 1(a12) { + }, + get "0.1"() { + return 42; + }, + set "0.1"(a15) { + }, + get "-1"() { + return 42; + }, + set "-1"(a18) { + }, + get $valid_id_42() { + return 42; + }, + set $valid_id_42(a21) { + }, + get "42_invalid_id"() { + return 42; + }, + set "42_invalid_id"(a24) { + }, + }; + + """ + XCTAssertEqual(actual, expected) + } + func testObjectLiteralIsDistinguishableFromBlockStatement() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -730,6 +805,11 @@ class LifterTests: XCTestCase { } cls.addInstanceSetter(for: "baz") { this, v in } + cls.addInstanceComputedGetter(for: baz) { this in + b.doReturn(b.loadInt(1337)) + } + cls.addInstanceComputedSetter(for: baz) { this, v in + } cls.addStaticProperty("foo") cls.addStaticInitializer { this in @@ -756,6 +836,11 @@ class LifterTests: XCTestCase { } cls.addStaticSetter(for: "baz") { this, v in } + cls.addStaticComputedGetter(for: baz) { this in + b.doReturn(b.loadInt(1337)) + } + cls.addStaticComputedSetter(for: baz) { this, v in + } cls.addPrivateInstanceProperty("ifoo") cls.addPrivateInstanceProperty("ibar", value: baz) @@ -815,6 +900,11 @@ class LifterTests: XCTestCase { } set baz(a17) { } + get ["baz"]() { + return 1337; + } + set ["baz"](a21) { + } static foo; static { this.foo = 42; @@ -834,29 +924,34 @@ class LifterTests: XCTestCase { static get baz() { return 1337; } - static set baz(a26) { + static set baz(a30) { + } + static get ["baz"]() { + return 1337; + } + static set ["baz"](a34) { } #ifoo; #ibar = "baz"; #im() { - const v28 = this.#ifoo; - this.#ibar = v28; - return v28; + const v36 = this.#ifoo; + this.#ibar = v36; + return v36; } - #in(a30) { + #in(a38) { this.#im(); - this.#ibar += a30; + this.#ibar += a38; } static #sfoo; static #sbar = "baz"; static #sm() { - const v33 = this.#sfoo; - this.#sbar = v33; - return v33; + const v41 = this.#sfoo; + this.#sbar = v41; + return v41; } - static #sn(a35) { + static #sn(a43) { this.#sm(); - this.#sbar += a35; + this.#sbar += a43; } } new C7(42); @@ -943,6 +1038,99 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testClassGetterSetterLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildClassDefinition() { cls in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + cls.addInstanceGetter(for: name) { this in + } + cls.addStaticGetter(for: name) { this in + } + cls.addInstanceSetter(for: name) { this, val in + } + cls.addStaticSetter(for: name) { this, val in + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C0 { + get "???"() { + } + static get "???"() { + } + set "???"(a4) { + } + static set "???"(a6) { + } + get 0() { + } + static get 0() { + } + set 0(a10) { + } + static set 0(a12) { + } + get "01"() { + } + static get "01"() { + } + set "01"(a16) { + } + static set "01"(a18) { + } + get 1() { + } + static get 1() { + } + set 1(a22) { + } + static set 1(a24) { + } + get "0.1"() { + } + static get "0.1"() { + } + set "0.1"(a28) { + } + static set "0.1"(a30) { + } + get "-1"() { + } + static get "-1"() { + } + set "-1"(a34) { + } + static set "-1"(a36) { + } + get $valid_id_42() { + } + static get $valid_id_42() { + } + set $valid_id_42(a40) { + } + static set $valid_id_42(a42) { + } + get "42_invalid_id"() { + } + static get "42_invalid_id"() { + } + set "42_invalid_id"(a46) { + } + static set "42_invalid_id"(a48) { + } + } + + """ + + XCTAssertEqual(actual, expected) + } + func testClassExpressionLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() From 16efb85be0c3d1648efcecd4d972cbf08561539c Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 1 Apr 2026 13:35:28 +0000 Subject: [PATCH 017/223] Transpile crashing instrumented programs from FuzzIL->JS->FuzzIL This CL transpiles crashing instrumented FuzzIL programs to JS (to insert the JS boilerplate code required for, e.g., explore()), and then transpiles this JS code back to FuzzIL and reports that program. This change will allow to apply Fuzzilli's own program minimization technique also on the boilerplate code. We hope that this will result in smaller reported programs. Bug: 488963988 Change-Id: I1e5ee51409c4c5e26db80e96d4f61060e12f0bd1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155916 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Parser/parser.js | 1 + .../Lifting/JavaScriptExploreLifting.swift | 6 +-- ...aScriptRuntimeAssistedMutatorLifting.swift | 4 +- .../Mutators/RuntimeAssistedMutator.swift | 24 ++++++++- .../RuntimeAssistedMutatorTests.swift | 53 ++++++++++++++++++- 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 4d5ece183..aa06d05ce 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -83,6 +83,7 @@ function parse(script, proto) { return Statement.create(statement); } + // TODO(bettscheider): Add support for default parameters. function visitParameter(param) { switch (param.type) { case 'Identifier': diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index 835263b95..f65dd3cca 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -342,7 +342,7 @@ struct JavaScriptExploreLifting { // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(COMPARISON_OPS, operation)) { if (isNaN(n)) { @@ -374,7 +374,7 @@ struct JavaScriptExploreLifting { // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(COMPARISON_OPS, operation)) { push(action.inputs, Inputs.randomBigintCloseTo(b)); @@ -395,7 +395,7 @@ struct JavaScriptExploreLifting { function exploreBoolean(b) { let operation = randomElement(ALL_BOOLEAN_OPERATIONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(BOOLEAN_BINARY_OPS, operation)) { // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index a1e1a0d69..17fba9d87 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -413,7 +413,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // // Action constructors. // - function Action(operation, inputs = EmptyArray()) { + function Action(operation, inputs) { this.operation = operation; this.inputs = inputs; this.isGuarded = false; @@ -431,7 +431,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // // If a guarded action succeeds (doesn't raise an exception), it will be converted to // a regular action to limit the number of generated try-catch blocks. - function GuardedAction(operation, inputs = EmptyArray()) { + function GuardedAction(operation, inputs) { this.operation = operation; this.inputs = inputs; this.isGuarded = true; diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 6a8b29c08..4e43be6e0 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -137,8 +137,30 @@ public class RuntimeAssistedMutator: Mutator { } // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. + // First, get the instrumented JS program and try to compile it back to FuzzIL, so it can be minimized more effectively. + // We need this because instrumentation adds boilerplate JS code. + let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) + var maybeProgramToMinimize: Program? = nil + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".js") + if let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]), + let parser = JavaScriptParser(executor: nodejs) { + do { + try instrumentedJavaScriptProgram.write(to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + } + try? FileManager.default.removeItem(at: tempFile) + } + else { + logger.warning("Unable to compile instrumented JS program to FuzzIL because node.js is not available") + } + + logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") - fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + fuzzer.processCrash(maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. break diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift index 9105c0544..4d1182b96 100644 --- a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -20,7 +20,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { var processArguments: [String] = [] var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { - if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") { + // Minimization can change quotation marks. Checking for both here to be on the safe side. + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") { return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } else { return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) @@ -79,4 +80,54 @@ class RuntimeAssistedMutatorTests: XCTestCase { _ = mutator.mutate(program, using: b, for: fuzzer) waitForExpectations(timeout: 5, handler: nil) } + + // This test checks that if *only* the instrumented program crashes, this program is minimized. + + func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { + guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { + throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + } + + // Initialize the parser. This can fail if no node.js executable is found or if the + // parser's node.js dependencies are not installed. In that case, skip these tests. + guard JavaScriptParser(executor: nodejs) != nil else { + throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + } + + class CrashEvaluator: MockEvaluator { + override func hasAspects(_ execution: Execution, _ aspects: ProgramAspects) -> Bool { + return execution.outcome.isCrash() + } + } + + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner, evaluator: CrashEvaluator()) + + let expectedProgramBuilder = fuzzer.makeBuilder() + let v0 = expectedProgramBuilder.loadString("FUZZILLI_CRASH") + let v1 = expectedProgramBuilder.loadInt(0) + let v2 = expectedProgramBuilder.createNamedVariable(forBuiltin: "fuzzilli") + expectedProgramBuilder.callFunction(v2, withArgs: [v0, v1]) + let expectedProgram = expectedProgramBuilder.finalize() + + let mutator = CrashingInstrumentationMutator(shouldProcessedProgramCrash: false) + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let actualProgram = ev.program + XCTAssertEqual(expectedProgram, actualProgram, + "The reported program should be the minimized version of the instrumented program.\n" + + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + crashEventTriggered.fulfill() + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } + } From 0ce37491c96ebd036b7299ee30a6682b5713812c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 14:17:58 +0200 Subject: [PATCH 018/223] [format] Add .swift-format with default settings Bug: 430616180 Change-Id: I168f494c2a1c0510fb6524495da4adb10ccd00cc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155816 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- .swift-format | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .swift-format diff --git a/.swift-format b/.swift-format new file mode 100644 index 000000000..9cfa61292 --- /dev/null +++ b/.swift-format @@ -0,0 +1,79 @@ +{ + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "indentBlankLines" : false, + "indentConditionalCompilationBlocks" : true, + "indentSwitchCaseLabels" : false, + "indentation" : { + "spaces" : 2 + }, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : false, + "lineBreakBeforeEachGenericRequirement" : false, + "lineBreakBetweenDeclarationAttributes" : false, + "lineLength" : 100, + "maximumBlankLines" : 1, + "multiElementCollectionTrailingCommas" : true, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow" + ] + }, + "orderedImports" : { + "includeConditionalImports" : false + }, + "prioritizeKeepingFunctionOutputTogether" : false, + "reflowMultilineStringLiterals" : "never", + "respectsExistingLineBreaks" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : true, + "AmbiguousTrailingClosureOverload" : true, + "AvoidRetroactiveConformances" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyLinesOpeningClosingBraces" : false, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoPlaygroundLiterals" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : false, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "TypeNamesShouldBeCapitalized" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : true, + "UseLetInEveryBoundCaseVariable" : true, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : true, + "UseSynthesizedInitializer" : true, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + }, + "spacesAroundRangeFormationOperators" : false, + "spacesBeforeEndOfLineComments" : 2, + "tabWidth" : 8, + "version" : 1 +} From 0f65b69f8026cec47162b30e5ac818fbc64a2f27 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 14:19:06 +0200 Subject: [PATCH 019/223] [format] Change indentation to 4 spaces To align better with the current formatting. No other reason. Also add a few swift-ignore-format annotations for weights. Bug: 430616180 Change-Id: I07b5dae4938578a49ec393faaf18959e2867e58f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155817 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- .swift-format | 2 +- Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.swift-format b/.swift-format index 9cfa61292..36423a346 100644 --- a/.swift-format +++ b/.swift-format @@ -6,7 +6,7 @@ "indentConditionalCompilationBlocks" : true, "indentSwitchCaseLabels" : false, "indentation" : { - "spaces" : 2 + "spaces" : 4 }, "lineBreakAroundMultilineExpressionChainComponents" : false, "lineBreakBeforeControlFlowKeywords" : false, diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index a26982e9c..f41d08997 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -13,6 +13,7 @@ // limitations under the License. /// Default weights for the builtin code generators. +// swift-format-ignore public let codeGeneratorWeights = [ // Value generators. These are used to bootstrap code // generation and therefore control the types of variables diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift index f642ceab8..c7274f4ad 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift @@ -13,6 +13,7 @@ // limitations under the License. /// Default weights for the builtin program templates. +// swift-format-ignore public let programTemplateWeights = [ "Codegen100": 2, "Codegen50": 2, From e4732f007933e842d7125139f30488b953c43ee4 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 15:00:54 +0200 Subject: [PATCH 020/223] [wasm] Make lifting more robust for tags The implicit import mechanism in Wasm needs a rework sooner or later. For now, let's make it more robust in this case. Fixed: 498266575 Change-Id: I17cc0021cbe945d5db16029c451e3ea6bfb55ff1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159837 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index c3e880992..d57adaf38 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -772,7 +772,7 @@ public class WasmLifter { temp += mutability ? [0x1] : [0x0] continue } - if type.Is(.object(ofGroup: "WasmTag")) { + if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { temp += [0x4, 0x0] + Leb128.unsignedEncode(try getSignatureIndex(signature!)) continue } From eff49a5cbcffc15a69d4ac97d6b1b1dfdc40652b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Wed, 1 Apr 2026 20:55:10 +0200 Subject: [PATCH 021/223] [js] Improve Iterator.zip fuzzing by passing it an iterable of iterables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9e7e47344d5c9fb3e56545be210788e1d8e492ef Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155596 Commit-Queue: Marja Hölttä Reviewed-by: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index f41d08997..3fb6330d7 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -225,6 +225,7 @@ public let codeGeneratorWeights = [ "ApiMethodCallGenerator": 15, "ApiFunctionCallGenerator": 15, "VoidGenerator": 1, + "IteratorZipGenerator": 1, // JS generators for wasm features (e.g. APIs on the WebAssembly global object). "WasmGlobalGenerator": 4, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index dfa73e95f..c7ae98ce8 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1870,6 +1870,38 @@ public let CodeGenerators: [CodeGenerator] = [ b.void(val) }, + CodeGenerator("IteratorZipGenerator", inputs: .one) { b, val in + // Create an iterable of iterables + let iterable : Variable; + let topLevelIterableSize = Int.random(in: 0...10) + if probability(0.8) { + // Use Array as the top level iterable + let iterables = (0.. Date: Wed, 1 Apr 2026 19:52:30 +0200 Subject: [PATCH 022/223] [js] Lower RAB/GSAB related weights back to what they were RAB/GSAB was shipped a while ago, we don't need the boosted weights any more Change-Id: Ic7da221bc2d47b1966906566d1e0ca4616251153 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9160936 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 3fb6330d7..69a29a2ef 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -210,13 +210,13 @@ public let codeGeneratorWeights = [ "EvalGenerator": 3, "NumberComputationGenerator": 40, "ImitationGenerator": 30, - "ResizableArrayBufferGenerator": 5*6, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. - "ResizableBufferResizeGenerator": 5*3, - "GrowableSharedArrayBufferGenerator": 5*6, - "GrowableSharedBufferGrowGenerator": 5*3, - "TypedArrayFromBufferGenerator": 10*3, - "DataViewFromBufferGenerator": 5*3, - "TypedArrayLastIndexGenerator": 5*3, + "ResizableArrayBufferGenerator": 5, + "ResizableBufferResizeGenerator": 5, + "GrowableSharedArrayBufferGenerator": 5, + "GrowableSharedBufferGrowGenerator": 5, + "TypedArrayFromBufferGenerator": 10, + "DataViewFromBufferGenerator": 5, + "TypedArrayLastIndexGenerator": 5, "FastToSlowPropertiesGenerator": 10, "IteratorGenerator": 5, "ConstructWithDifferentNewTargetGenerator": 5, @@ -230,9 +230,9 @@ public let codeGeneratorWeights = [ // JS generators for wasm features (e.g. APIs on the WebAssembly global object). "WasmGlobalGenerator": 4, "WasmMemoryGenerator": 4, - "WasmMemoryToResizableBufferGenerator": 5*3, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. - "WasmMemoryToFixedLengthBufferGenerator": 5*3, - "WasmMemoryJSGrowGenerator": 5*3, + "WasmMemoryToResizableBufferGenerator": 5, + "WasmMemoryToFixedLengthBufferGenerator": 5, + "WasmMemoryJSGrowGenerator": 5, "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, From e270121d8ed2c1101ef1717dc6a5a2aa2607a381 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 12:35:03 +0200 Subject: [PATCH 023/223] [js] Improve labels for ProgramBuilder.reassign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If51387c564c5c4245d23122be751ce46682b0fee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159756 Commit-Queue: Matthias Liedtke Reviewed-by: Marja Hölttä Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 8 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 6 +- .../Fuzzilli/Profiles/V8CommonProfile.swift | 16 ++-- Sources/Fuzzilli/Profiles/XSProfile.swift | 12 +-- Tests/FuzzilliTests/JSTyperTests.swift | 74 ++++++++--------- Tests/FuzzilliTests/LifterTest.swift | 80 +++++++++---------- Tests/FuzzilliTests/MinimizerTest.swift | 40 +++++----- Tests/FuzzilliTests/ProgramBuilderTest.swift | 18 ++--- 8 files changed, 127 insertions(+), 127 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index d29c09b88..657fec431 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3200,8 +3200,8 @@ public class ProgramBuilder { return emit(TernaryOperation(), withInputs: [condition, lhs, rhs]).output } - public func reassign(_ output: Variable, to input: Variable, with op: BinaryOperator) { - emit(Update(op), withInputs: [output, input]) + public func reassign(variable: Variable, value: Variable, with op: BinaryOperator) { + emit(Update(op), withInputs: [variable, value]) } @discardableResult @@ -3209,8 +3209,8 @@ public class ProgramBuilder { return emit(Dup(), withInputs: [v]).output } - public func reassign(_ output: Variable, to input: Variable) { - emit(Reassign(), withInputs: [output, input]) + public func reassign(variable: Variable, value: Variable) { + emit(Reassign(), withInputs: [variable, value]) } @discardableResult diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index c7ae98ce8..05ef29b52 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1420,7 +1420,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("BuiltinOverwriteGenerator", inputs: .one) { b, value in let builtin = b.createNamedVariable( b.randomBuiltin(), declarationMode: .none) - b.reassign(builtin, to: value) + b.reassign(variable: builtin, value: value) }, CodeGenerator("PlainFunctionGenerator", [ @@ -2104,7 +2104,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("UpdateGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) b.reassign( - newValue, to: v, with: chooseUniform(from: BinaryOperator.allCases)) + variable: newValue, value: v, with: chooseUniform(from: BinaryOperator.allCases)) }, CodeGenerator("DupGenerator") { b in @@ -2114,7 +2114,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("ReassignmentGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) guard newValue != v else { return } - b.reassign(newValue, to: v) + b.reassign(variable: newValue, value: v) }, CodeGenerator("DestructArrayGenerator", inputs: .preferred(.iterable)) { diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 43a004e68..6fb2fe379 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -522,11 +522,11 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let symbol = b.createNamedVariable(forBuiltin: "Symbol") withEqualProbability({ let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("match", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("replace", of: symbol) let replacement = withEqualProbability({ @@ -535,11 +535,11 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.loadString(chooseUniform(from: replacementCandidates)) }) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("search", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("split", of: symbol) let randomSplitLimit = withEqualProbability({ @@ -551,10 +551,10 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in }) let limit = b.loadString(randomSplitLimit) let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }) }, catchBody: { _ in }) @@ -590,7 +590,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in b.build(n: 10) b.buildIf(b.compare(counter, with: max, using: .lessThan)) { - b.reassign(counter, to: b.binary(counter, b.loadInt(1), with: .Add)) + b.reassign(variable: counter, value: b.binary(counter, b.loadInt(1), with: .Add)) b.callFunction(dummyFct, withArgs: b.randomArguments(forCalling: dummyFct)) } // Mark the function for deoptimization. Due to the recursive pattern above, on the outer @@ -601,7 +601,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in } // Turn the call into a recursive call. - b.reassign(dummyFct, to: realFct) + b.reassign(variable: dummyFct, value: realFct) let args = b.randomArguments(forCalling: realFct) let guardCalls = probability(0.5) b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); diff --git a/Sources/Fuzzilli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift index 02c500c97..8037aca28 100644 --- a/Sources/Fuzzilli/Profiles/XSProfile.swift +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -181,11 +181,11 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let symbol = b.createNamedVariable(forBuiltin: "Symbol") withEqualProbability({ let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("match", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("replace", of: symbol) let replacement = withEqualProbability({ @@ -194,11 +194,11 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.loadString(chooseUniform(from: replacementCandidates)) }) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("search", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("split", of: symbol) let randomSplitLimit = withEqualProbability({ @@ -210,10 +210,10 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in }) let limit = b.loadString(randomSplitLimit) let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }) }, catchBody: { _ in }) diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index ebc6a7fe3..20f549f2b 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -131,7 +131,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) XCTAssertEqual(b.type(of: params[1]), .string) XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: params[1]) + b.reassign(variable: v, value: params[1]) XCTAssertEqual(b.type(of: v), .string) } @@ -143,7 +143,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) XCTAssertEqual(b.type(of: params[1]), .float) XCTAssertEqual(b.type(of: v), .integer | .string) - b.reassign(v, to: params[1]) + b.reassign(variable: v, value: params[1]) XCTAssertEqual(b.type(of: v), .float) } @@ -205,7 +205,7 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .float) } @@ -214,8 +214,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer | .float) XCTAssertEqual(b.type(of: f), .float) - b.reassign(v, to: b.loadString("bar")) - b.reassign(f, to: b.loadString("baz")) + b.reassign(variable: v, value: b.loadString("bar")) + b.reassign(variable: f, value: b.loadString("baz")) XCTAssertEqual(b.type(of: v), .jsString) XCTAssertEqual(b.type(of: f), .jsString) @@ -225,8 +225,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer | .float | .jsString) XCTAssertEqual(b.type(of: s), .jsString) - b.reassign(v, to: b.loadBool(true)) - b.reassign(s, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadBool(true)) + b.reassign(variable: s, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .boolean) XCTAssertEqual(b.type(of: s), .float) @@ -239,7 +239,7 @@ class JSTyperTests: XCTestCase { cls.addStaticInitializer { this in XCTAssertEqual(b.type(of: f), .float | .jsString) - b.reassign(f, to: b.loadBool(true)) + b.reassign(variable: f, value: b.loadBool(true)) XCTAssertEqual(b.type(of: f), .boolean) } @@ -530,11 +530,11 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) XCTAssertEqual(b.type(of: v), .float) let objVar = b.createObject(with: ["foo": b.loadInt(1337)]) - b.reassign(v, to: objVar) + b.reassign(variable: v, value: objVar) XCTAssertEqual(b.type(of: v), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) } @@ -553,7 +553,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let stringVar = b.loadString("foobar") - b.reassign(v, to: stringVar) + b.reassign(variable: v, value: stringVar) XCTAssertEqual(b.type(of: v), .jsString) }, elseBody: { XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) @@ -563,7 +563,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) }) XCTAssertEqual(b.type(of: v), .string | .float | .object() | .iterable) @@ -577,10 +577,10 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) XCTAssertEqual(b.type(of: v1), .integer) b.buildIfElse(v0, ifBody: { - b.reassign(v0, to: b.loadString("foo")) - b.reassign(v1, to: b.loadString("foo")) + b.reassign(variable: v0, value: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) }, elseBody: { - b.reassign(v1, to: b.loadString("bar")) + b.reassign(variable: v1, value: b.loadString("bar")) }) XCTAssertEqual(b.type(of: v0), .integer | .jsString) @@ -593,7 +593,7 @@ class JSTyperTests: XCTestCase { let i = b.loadInt(42) XCTAssertEqual(b.type(of: i), .integer) b.buildIf(i) { - b.reassign(i, to: b.loadString("foo")) + b.reassign(variable: i, value: b.loadString("foo")) } XCTAssertEqual(b.type(of: i), .integer | .jsString) @@ -609,11 +609,11 @@ class JSTyperTests: XCTestCase { b.buildIfElse(v, ifBody: { b.buildIfElse(v, ifBody: { b.buildIfElse(v, ifBody: { - b.reassign(v, to: b.loadString("foo")) + b.reassign(variable: v, value: b.loadString("foo")) XCTAssertEqual(b.type(of: v), .jsString) }, elseBody: { XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: b.loadBool(true)) + b.reassign(variable: v, value: b.loadBool(true)) XCTAssertEqual(b.type(of: v), .boolean) }) @@ -641,7 +641,7 @@ class JSTyperTests: XCTestCase { params in XCTAssertEqual(b.type(of: params[0]), .integer) } XCTAssertEqual(b.type(of: f), .functionAndConstructor(signature)) - b.reassign(f, to: b.loadString("foo")) + b.reassign(variable: f, value: b.loadString("foo")) XCTAssertEqual(b.type(of: f), .jsString) } } @@ -663,7 +663,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .jsString) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v), .float) @@ -995,14 +995,14 @@ class JSTyperTests: XCTestCase { // Logical operators produce .boolean in any case guard op != .LogicOr && op != .LogicAnd else { continue } - b.reassign(i3, to: i4, with: op) + b.reassign(variable: i3, value: i4, with: op) XCTAssertFalse(b.type(of: i3).MayBe(.bigint)) - b.reassign(i3, to: bi4, with: op) + b.reassign(variable: i3, value: bi4, with: op) // This isn't really necessary, as mixing types in this way // would lead to an exception in JS. Currently, we handle // it like this though. XCTAssert(b.type(of: i3).MayBe(.bigint)) - b.reassign(bi3, to: bi4, with: op) + b.reassign(variable: bi3, value: bi4, with: op) XCTAssert(b.type(of: bi3).Is(.bigint)) } } @@ -1014,8 +1014,8 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // The header executes unconditionally, but the body does not - b.buildWhileLoop({ b.reassign(v1, to: b.loadString("foo")); return b.loadBool(false) }) { - b.reassign(v2, to: b.loadString("bar")) + b.buildWhileLoop({ b.reassign(variable: v1, value: b.loadString("foo")); return b.loadBool(false) }) { + b.reassign(variable: v2, value: b.loadString("bar")) } XCTAssertEqual(b.type(of: v1), .jsString) @@ -1030,8 +1030,8 @@ class JSTyperTests: XCTestCase { let v2 = b.loadInt(1) // Both the header and the body execute unconditionally b.buildDoWhileLoop(do: { - b.reassign(v2, to: b.loadString("foo")) - }, while: { b.reassign(v1, to: b.loadString("bar")); return b.loadBool(false) }) + b.reassign(variable: v2, value: b.loadString("foo")) + }, while: { b.reassign(variable: v1, value: b.loadString("bar")); return b.loadBool(false) }) XCTAssertEqual(b.type(of: v1), .jsString) XCTAssertEqual(b.type(of: v2), .jsString) @@ -1048,14 +1048,14 @@ class JSTyperTests: XCTestCase { // The initializer block and the condition block are always executed. // The afterthought and body block may not be executed. b.buildForLoop({ - b.reassign(v1, to: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) }, { - b.reassign(v2, to: b.loadString("bar")) + b.reassign(variable: v2, value: b.loadString("bar")) return b.loadBool(false) }, { - b.reassign(v3, to: b.loadString("baz")) + b.reassign(variable: v3, value: b.loadString("baz")) }) { - b.reassign(v4, to: b.loadString("bla")) + b.reassign(variable: v4, value: b.loadString("bla")) } XCTAssertEqual(b.type(of: v1), .jsString) @@ -1107,7 +1107,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let stringVar = b.loadString("foobar") - b.reassign(v0, to: stringVar) + b.reassign(variable: v0, value: stringVar) XCTAssertEqual(b.type(of: v0), .jsString) } swtch.addDefaultCase { @@ -1118,7 +1118,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let boolVal = b.loadBool(false) - b.reassign(v0, to: boolVal) + b.reassign(variable: v0, value: boolVal) XCTAssertEqual(b.type(of: v0), .boolean) } swtch.addCase(v4) { @@ -1129,7 +1129,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v0, to: floatVar) + b.reassign(variable: v0, value: floatVar) XCTAssertEqual(b.type(of: v0), .float) } } @@ -1150,7 +1150,7 @@ class JSTyperTests: XCTestCase { swtch.addDefaultCase { XCTAssertEqual(b.type(of: i1), .integer) XCTAssertEqual(b.type(of: i2), .integer) - b.reassign(i2, to: b.loadString("bar")) + b.reassign(variable: i2, value: b.loadString("bar")) } } @@ -1171,13 +1171,13 @@ class JSTyperTests: XCTestCase { b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { XCTAssertEqual(b.type(of: v), .jsString) - b.reassign(v, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .float) } swtch.addCase(i3) { XCTAssertEqual(b.type(of: v), .jsString) - b.reassign(v, to: b.loadBool(false)) + b.reassign(variable: v, value: b.loadBool(false)) XCTAssertEqual(b.type(of: v), .boolean) } } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 9308fa71a..0f1a51621 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -334,7 +334,7 @@ class LifterTests: XCTestCase { b.createArray(with: [n1, n1, n1]) // ... but when it's reassigned, the identifier needs to be stored to a local variable. let n2 = b.loadFloat(Double.nan) - b.reassign(n2, to: b.loadFloat(13.37)) + b.reassign(variable: n2, value: b.loadFloat(13.37)) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -870,7 +870,7 @@ class LifterTests: XCTestCase { } } b.construct(C, withArgs: [b.loadInt(42)]) - b.reassign(C, to: b.createNamedVariable(forBuiltin: "Uint8Array")) + b.reassign(variable: C, value: b.createNamedVariable(forBuiltin: "Uint8Array")) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -1194,7 +1194,7 @@ class LifterTests: XCTestCase { initialValues.append(b.loadUndefined()) initialValues.append(b.loadInt(6)) let v = b.loadString("foobar") - b.reassign(v, to: b.loadUndefined()) + b.reassign(variable: v, value: b.loadUndefined()) initialValues.append(v) let va = b.createArray(with: initialValues) b.createArray(with: [b.loadInt(301), b.loadUndefined()]) @@ -1363,7 +1363,7 @@ class LifterTests: XCTestCase { let f2 = b.buildArrowFunction(with: .parameters(n: 0)) { args in b.doReturn(b.loadString("foobar")) } - b.reassign(f, to: f2) + b.reassign(variable: f, value: f2) b.callFunction(f) let program = b.finalize() @@ -1483,7 +1483,7 @@ class LifterTests: XCTestCase { } b.construct(c1, withArgs: [b.loadInt(42), b.loadInt(43)]) let c2 = b.createNamedVariable(forBuiltin: "Object") - b.reassign(c1, to: c2) + b.reassign(variable: c1, value: c2) b.construct(c1, withArgs: [b.loadInt(44), b.loadInt(45)]) let program = b.finalize() @@ -1569,9 +1569,9 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(1337) let v1 = b.loadFloat(13.37) - b.reassign(v0, to: v1, with: .Add) + b.reassign(variable: v0, value: v1, with: .Add) let v2 = b.loadString("Hello") - b.reassign(v1, to: v2) + b.reassign(variable: v1, value: v2) let v3 = b.loadInt(1336) let v4 = b.unary(.PreInc, v3) b.unary(.PostInc, v4) @@ -1599,12 +1599,12 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(1337) let v1 = b.loadFloat(13.37) - b.reassign(v0, to: v1, with: .Add) - b.reassign(v0, to: v1, with: .Mul) - b.reassign(v0, to: v1, with: .LShift) + b.reassign(variable: v0, value: v1, with: .Add) + b.reassign(variable: v0, value: v1, with: .Mul) + b.reassign(variable: v0, value: v1, with: .LShift) let v2 = b.loadString("hello") let v3 = b.loadString("world") - b.reassign(v2, to: v3, with: .Add) + b.reassign(variable: v2, value: v3, with: .Add) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -1630,38 +1630,38 @@ class LifterTests: XCTestCase { let bar = b.createNamedVariable(forBuiltin: "bar") let baz = b.createNamedVariable(forBuiltin: "baz") let i = b.loadInt(42) - b.reassign(i, to: b.loadInt(43)) + b.reassign(variable: i, value: b.loadInt(43)) b.callFunction(foo, withArgs: [i]) b.callFunction(bar, withArgs: [i]) let j = b.loadInt(44) - b.reassign(j, to: b.loadInt(45)) - b.reassign(j, to: b.loadInt(46)) + b.reassign(variable: j, value: b.loadInt(45)) + b.reassign(variable: j, value: b.loadInt(46)) b.callFunction(foo, withArgs: [j]) let k = b.loadInt(47) b.buildRepeatLoop(n: 10) { i in - b.reassign(k, to: i) + b.reassign(variable: k, value: i) } b.callFunction(foo, withArgs: [k]) let l = b.loadInt(48) - b.reassign(l, to: b.loadInt(49)) + b.reassign(variable: l, value: b.loadInt(49)) b.callFunction(foo, withArgs: [l, l, l]) let m = b.loadInt(50) - b.reassign(m, to: b.loadInt(51)) + b.reassign(variable: m, value: b.loadInt(51)) var t = b.callFunction(baz) t = b.callFunction(bar, withArgs: [m, m, t, m]) b.callFunction(foo, withArgs: [t]) // Some operations such as element stores force the lhs to be an identifier, so test that here. let n = b.loadInt(52) - b.reassign(n, to: b.createArray(with: [])) + b.reassign(variable: n, value: b.createArray(with: [])) b.setElement(42, of: n, to: n) let o = b.loadInt(53) - b.buildWhileLoop({ b.reassign(o, to: i); return b.loadBool(false) }) { + b.buildWhileLoop({ b.reassign(variable: o, value: i); return b.loadBool(false) }) { } b.callFunction(foo, withArgs: [o]) @@ -1803,7 +1803,7 @@ class LifterTests: XCTestCase { b.doReturn(v) } let f2 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.reassign(v, to: args[0]) + b.reassign(variable: v, value: args[0]) } let num = b.loadInt(42) b.configureProperty("foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) @@ -1942,9 +1942,9 @@ class LifterTests: XCTestCase { let v3 = b.callMethod("n", on: o, guard: true) b.callComputedMethod(b.loadString("o"), on: o, withArgs: [v1, v2, v3], guard: true) let v4 = b.callComputedMethod(b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) - b.reassign(v3, to: b.loadString("foo")) - b.reassign(v4, to: b.loadString("bar")) - b.reassign(v3, to: b.loadString("baz")) + b.reassign(variable: v3, value: b.loadString("foo")) + b.reassign(variable: v4, value: b.loadString("bar")) + b.reassign(variable: v3, value: b.loadString("baz")) let program = b.finalize() @@ -2687,7 +2687,7 @@ class LifterTests: XCTestCase { b.callFunction(print, withArgs: [vb1]) b.createNamedVariable("c", declarationMode: .global, initialValue: i2) let vb2 = b.createNamedVariable("b", declarationMode: .var, initialValue: i2) - b.reassign(vb2, to: i1) + b.reassign(variable: vb2, value: i1) let vc = b.createNamedVariable("c", declarationMode: .none) b.callFunction(print, withArgs: [vc]) let undefined = b.loadUndefined() @@ -3196,7 +3196,7 @@ class LifterTests: XCTestCase { b.buildForLoop({ let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")); let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")); b.callFunction(b.createNamedVariable(forBuiltin: "h")); return [x, y] }, { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, - { vs in b.reassign(vs[0], to: vs[1], with: .Add) }) { vs in + { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) }) { vs in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: vs) } @@ -3228,7 +3228,7 @@ class LifterTests: XCTestCase { { let shouldContinue = b.callFunction(b.createNamedVariable(forBuiltin: "shouldContinue")) b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { - b.reassign(shouldContinue, to: b.loadBool(false)) + b.reassign(variable: shouldContinue, value: b.loadBool(false)) } return shouldContinue }) { @@ -3260,7 +3260,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign($0, to: b.loadInt(10), with: .Add) }) { i in + b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) }) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) } @@ -3308,7 +3308,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(i, to: args[2], with: .Sub)}) { vars in + b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(variable: i, value: args[2], with: .Sub)}) { vars in } } @@ -3368,7 +3368,7 @@ class LifterTests: XCTestCase { // Test that context-dependent operations such as LoadArguments are handled correctly inside loop headers b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in let arg = b.getComputedProperty(i, of: b.loadArguments()) - b.reassign(s, to: arg, with: .Add) + b.reassign(variable: s, value: arg, with: .Add) } b.doReturn(s) } @@ -3396,7 +3396,7 @@ class LifterTests: XCTestCase { let s = b.loadInt(0) b.buildRepeatLoop(n: 1337) { i in - b.reassign(s, to: i, with: .Add) + b.reassign(variable: s, value: i, with: .Add) } let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [s]) @@ -3457,10 +3457,10 @@ class LifterTests: XCTestCase { b.buildForInLoop(v1) { v2 in b.blockStatement { let v3 = b.loadInt(1337) - b.reassign(v2, to: v3) + b.reassign(variable: v2, value: v3) b.blockStatement { let v4 = b.createObject(with: ["a" : v1]) - b.reassign(v2, to: v4) + b.reassign(variable: v2, value: v4) } } @@ -3581,24 +3581,24 @@ class LifterTests: XCTestCase { let this = b.loadThis() let v = b.loadInt(42) - b.reassign(this, to: v) + b.reassign(variable: this, value: v) b.buildConstructor(with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } b.buildObjectLiteral { obj in obj.addMethod("foo", with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } } b.buildClassDefinition { cls in cls.addInstanceMethod("bar", with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } cls.addStaticGetter(for: "baz") { this in - b.reassign(this, to: v) + b.reassign(variable: this, value: v) } } @@ -3657,7 +3657,7 @@ class LifterTests: XCTestCase { b.unary(.BitwiseNot, v0) b.binary(v0, v2, with: .Add) let v3 = b.loadInt(42) - b.reassign(v3, to: v0) + b.reassign(variable: v3, value: v0) let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [v0, v1, v2]) b.getProperty("foo", of: v1) @@ -3691,7 +3691,7 @@ class LifterTests: XCTestCase { let variable = b.loadNull() b.buildPlainFunction(with: .parameters(n: 0)) { args in let t = b.loadNewTarget() - b.reassign(variable, to: t) + b.reassign(variable: variable, value: t) } let program = b.finalize() @@ -3836,7 +3836,7 @@ class LifterTests: XCTestCase { // We will mutate this to reassign table to be f. // The steps for this to happen during fuzzing are as follows, we emit all of this during generation time, then we emit this reassign later, e.g. during CodeGenMutation or we change an existing reassign during InputMutation. // Then we need to be able to recover from this in the importAnalysis as this is the first code that tries to use the mistyped inputs. - b.reassign(table, to: table) + b.reassign(variable: table, value: table) b.buildWasmModule { m in m.addWasmFunction(with: [] => []) { f, _, _ in diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index b874ca9c6..2878c9431 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -355,7 +355,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -408,7 +408,7 @@ class MinimizerTests: XCTestCase { swtch.addDefaultCase(fallsThrough: false) { evaluator.nextInstructionIsImportant(in: b) let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -466,7 +466,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -510,7 +510,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -637,9 +637,9 @@ class MinimizerTests: XCTestCase { let u = b.loadUndefined() r = b.loadUndefined() b.buildIfElse(a1, ifBody: { - b.reassign(r, to: a2) + b.reassign(variable: r, value: a2) }, elseBody: { - b.reassign(r, to: u) + b.reassign(variable: r, value: u) }) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: r) @@ -711,9 +711,9 @@ class MinimizerTests: XCTestCase { a3 = b.loadInt(2) r = b.loadUndefined() b.buildIf(a1, ifBody: { - b.reassign(r, to: a2) + b.reassign(variable: r, value: a2) }) - b.reassign(r, to: a3) + b.reassign(variable: r, value: a3) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: a3) @@ -835,25 +835,25 @@ class MinimizerTests: XCTestCase { var n1 = b.loadInt(42) var n2 = b.loadInt(43) var n3 = b.loadInt(44) - b.reassign(n3, to: n1) + b.reassign(variable: n3, value: n1) var n4 = b.loadInt(45) - b.reassign(n4, to: n3) + b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 var c = b.loadBool(true) b.buildIfElse(c, ifBody: { let n5 = b.loadInt(46) - b.reassign(n1, to: n5) + b.reassign(variable: n1, value: n5) b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 }, elseBody: { let n6 = b.loadInt(47) - b.reassign(n1, to: n6) + b.reassign(variable: n1, value: n6) b.setProperty( "n3", of: o, to: n3) // This will still store n3, i.e. 42 }) b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 evaluator.operationIsImportant(Reassign.self) @@ -869,26 +869,26 @@ class MinimizerTests: XCTestCase { n1 = b.loadInt(42) n2 = b.loadInt(43) n3 = b.loadInt(44) - b.reassign(n3, to: n1) + b.reassign(variable: n3, value: n1) n4 = b.loadInt(45) - b.reassign(n4, to: n3) + b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n1) c = b.loadBool(true) b.buildIfElse(c, ifBody: { let n5 = b.loadInt(46) - b.reassign(n1, to: n5) + b.reassign(variable: n1, value: n5) b.setProperty("n1", of: o, to: n5) b.setProperty("n1", of: o, to: n5) - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n1", of: o, to: n2) }, elseBody: { let n6 = b.loadInt(47) - b.reassign(n1, to: n6) + b.reassign(variable: n1, value: n6) b.setProperty("n3", of: o, to: n3) }) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n1", of: o, to: n1) - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n3", of: o, to: n3) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 5f495f0dc..7dc3dfd2a 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2007,7 +2007,7 @@ class ProgramBuilderTests: XCTestCase { b.buildPlainFunction(with: .parameters(n: 1)) { args in let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(f2, to: b.loadFloat(133.7)) + b.reassign(variable: f2, value: b.loadFloat(133.7)) let o = b.createObject(with: ["i": i, "f": f]) let o2 = b.createObject(with: ["i": i, "f": f2]) b.binary(i, args[0], with: .Add) @@ -2035,7 +2035,7 @@ class ProgramBuilderTests: XCTestCase { f2 = b.loadFloat(13.37) let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(f2, to: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included + b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included let o = b.createObject(with: ["i": i, "f": f]) b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included let object = b.createNamedVariable(forBuiltin: "Object") @@ -2343,7 +2343,7 @@ class ProgramBuilderTests: XCTestCase { b.throwException(v) }, catchBody: { e in splicePoint = b.indexOfNextInstruction() - b.reassign(e, to: s) + b.reassign(variable: e, value: s) }) let original = b.finalize() @@ -2459,13 +2459,13 @@ class ProgramBuilderTests: XCTestCase { splicePoint = b.indexOfNextInstruction() b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { - b.reassign(s, to: b.loadString("Bar")) + b.reassign(variable: s, value: b.loadString("Bar")) } swtch.addCase(i3) { - b.reassign(s, to: b.loadString("Baz")) + b.reassign(variable: s, value: b.loadString("Baz")) } swtch.addDefaultCase { - b.reassign(s, to: b.loadString("Bla")) + b.reassign(variable: s, value: b.loadString("Bla")) } } let original = b.finalize() @@ -2493,13 +2493,13 @@ class ProgramBuilderTests: XCTestCase { var s = b.loadString("Foo") b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { - b.reassign(s, to: b.loadString("Bar")) + b.reassign(variable: s, value: b.loadString("Bar")) } swtch.addCase(i3) { - b.reassign(s, to: b.loadString("Baz")) + b.reassign(variable: s, value: b.loadString("Baz")) } swtch.addDefaultCase { - b.reassign(s, to: b.loadString("Bla")) + b.reassign(variable: s, value: b.loadString("Bla")) } } let original = b.finalize() From c523132767b1e7061307c08d22b75f218b3d7b4b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 12:39:59 +0200 Subject: [PATCH 024/223] [js] Fix order of reassignment logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostly just to match the naming of `newValue` and the subtyping idea of the forUseAs where we try to find something that is a subtype of the current variable's type, not the other way around. Change-Id: I3144025a0e1850892936087fdf275d318943f963 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159757 Reviewed-by: Marja Hölttä Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 05ef29b52..d8f8890fd 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2104,7 +2104,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("UpdateGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) b.reassign( - variable: newValue, value: v, with: chooseUniform(from: BinaryOperator.allCases)) + variable: v, value: newValue, with: chooseUniform(from: BinaryOperator.allCases)) }, CodeGenerator("DupGenerator") { b in @@ -2114,7 +2114,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("ReassignmentGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) guard newValue != v else { return } - b.reassign(variable: newValue, value: v) + b.reassign(variable: v, value: newValue) }, CodeGenerator("DestructArrayGenerator", inputs: .preferred(.iterable)) { From 96773dbfb1f66483db0c23ed3819ec5249b7709c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 2 Apr 2026 14:04:02 +0200 Subject: [PATCH 025/223] [format] Apply auto-formatting Bug: 430616180 Change-Id: I12f41e8c87913481f05f3bf350acdb88ac08c163 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155818 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Package.swift | 92 +- Sources/FuzzILTool/main.swift | 69 +- Sources/Fuzzilli/Base/ContextGraph.swift | 42 +- Sources/Fuzzilli/Base/Contributor.swift | 3 +- Sources/Fuzzilli/Base/Events.swift | 10 +- Sources/Fuzzilli/Base/Logging.swift | 6 +- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2718 ++++++---- Sources/Fuzzilli/Base/Timers.swift | 6 +- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 330 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 708 +-- .../Fuzzilli/CodeGen/ProgramTemplate.swift | 5 +- .../Fuzzilli/CodeGen/ProgramTemplates.swift | 196 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 607 ++- Sources/Fuzzilli/Compiler/Compiler.swift | 444 +- .../Fuzzilli/Compiler/JavaScriptParser.swift | 6 +- Sources/Fuzzilli/Configuration.swift | 43 +- Sources/Fuzzilli/Corpus/BasicCorpus.swift | 2 +- Sources/Fuzzilli/Corpus/Corpus.swift | 6 +- Sources/Fuzzilli/Corpus/MarkovCorpus.swift | 6 +- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 69 +- Sources/Fuzzilli/Engines/FuzzEngine.swift | 92 +- Sources/Fuzzilli/Engines/HybridEngine.swift | 36 +- Sources/Fuzzilli/Engines/MultiEngine.swift | 8 +- Sources/Fuzzilli/Engines/MutationEngine.swift | 3 +- .../Environment/JavaScriptEnvironment.swift | 3639 +++++++++----- .../Evaluation/ProgramCoverageEvaluator.swift | 46 +- .../Evaluation/ProgramEvaluator.swift | 3 +- Sources/Fuzzilli/Execution/Execution.swift | 25 +- Sources/Fuzzilli/Execution/REPRL.swift | 34 +- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 12 +- Sources/Fuzzilli/FuzzIL/Blocks.swift | 1 - Sources/Fuzzilli/FuzzIL/Code.swift | 31 +- Sources/Fuzzilli/FuzzIL/Context.swift | 30 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 934 ++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 963 ++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 520 +- Sources/Fuzzilli/FuzzIL/Operation.swift | 29 +- Sources/Fuzzilli/FuzzIL/Program.swift | 11 +- Sources/Fuzzilli/FuzzIL/ProgramComments.swift | 2 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 39 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 669 ++- Sources/Fuzzilli/FuzzIL/Variable.swift | 4 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 740 +-- Sources/Fuzzilli/Fuzzer.swift | 356 +- Sources/Fuzzilli/Lifting/Expression.swift | 20 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 353 +- Sources/Fuzzilli/Lifting/JSExpressions.swift | 53 +- .../Lifting/JavaScriptExploreLifting.swift | 810 +-- .../Lifting/JavaScriptFixupLifting.swift | 196 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 700 +-- .../Lifting/JavaScriptProbeLifting.swift | 224 +- ...aScriptRuntimeAssistedMutatorLifting.swift | 1090 ++-- Sources/Fuzzilli/Lifting/ScriptWriter.swift | 14 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 583 ++- .../Fuzzilli/Minimization/BlockReducer.swift | 157 +- .../Minimization/DataFlowSimplifier.swift | 18 +- .../Minimization/DeduplicatingReducer.swift | 8 +- .../Minimization/InliningReducer.swift | 94 +- .../Minimization/InstructionSimplifier.swift | 43 +- .../Minimization/LoopSimplifier.swift | 110 +- .../Minimization/MinimizationHelper.swift | 70 +- .../MinimizationPostProcessor.swift | 60 +- Sources/Fuzzilli/Minimization/Minimizer.swift | 43 +- .../Minimization/VariadicInputReducer.swift | 32 +- .../Minimization/WasmTypeGroupReducer.swift | 14 +- Sources/Fuzzilli/Modules/NetworkSync.swift | 101 +- Sources/Fuzzilli/Modules/Statistics.swift | 34 +- Sources/Fuzzilli/Modules/Storage.swift | 47 +- Sources/Fuzzilli/Modules/Sync.swift | 87 +- Sources/Fuzzilli/Modules/ThreadSync.swift | 17 +- .../Mutators/BaseInstructionMutator.swift | 7 +- .../Fuzzilli/Mutators/CodeGenMutator.swift | 7 +- Sources/Fuzzilli/Mutators/ConcatMutator.swift | 4 +- .../Mutators/ExplorationMutator.swift | 31 +- Sources/Fuzzilli/Mutators/FixupMutator.swift | 123 +- Sources/Fuzzilli/Mutators/InputMutator.swift | 18 +- .../Fuzzilli/Mutators/MutatorSettings.swift | 3 +- .../Fuzzilli/Mutators/OperationMutator.swift | 793 +-- .../Fuzzilli/Mutators/ProbingMutator.swift | 62 +- .../Mutators/RuntimeAssistedMutator.swift | 122 +- Sources/Fuzzilli/Mutators/SpliceMutator.swift | 3 +- .../Fuzzilli/Profiles/DuktapeProfile.swift | 19 +- Sources/Fuzzilli/Profiles/JSCProfile.swift | 52 +- .../Profiles/JerryscriptProfile.swift | 15 +- Sources/Fuzzilli/Profiles/NjsProfile.swift | 5 +- Sources/Fuzzilli/Profiles/Profile.swift | 3 +- Sources/Fuzzilli/Profiles/QjsProfile.swift | 7 +- Sources/Fuzzilli/Profiles/QtjsProfile.swift | 16 +- Sources/Fuzzilli/Profiles/Serenity.swift | 13 +- .../Profiles/SpidermonkeyProfile.swift | 33 +- .../Fuzzilli/Profiles/V8CommonProfile.swift | 559 ++- .../Fuzzilli/Profiles/V8DumplingProfile.swift | 128 +- .../Profiles/V8HoleFuzzingProfile.swift | 29 +- Sources/Fuzzilli/Profiles/V8Profile.swift | 74 +- .../Fuzzilli/Profiles/V8SandboxProfile.swift | 627 +-- Sources/Fuzzilli/Profiles/XSProfile.swift | 250 +- Sources/Fuzzilli/Protobuf/ProtoUtils.swift | 13 +- Sources/Fuzzilli/Util/Arguments.swift | 4 +- Sources/Fuzzilli/Util/CInterop.swift | 12 +- .../Fuzzilli/Util/JavaScriptExecutor.swift | 88 +- Sources/Fuzzilli/Util/MockFuzzer.swift | 87 +- Sources/Fuzzilli/Util/Random.swift | 8 +- Sources/Fuzzilli/Util/VariableMap.swift | 2 +- Sources/Fuzzilli/Util/VariableSet.swift | 2 +- Sources/FuzzilliCli/TerminalUI.swift | 90 +- Sources/FuzzilliCli/main.swift | 431 +- .../FuzzilliDetectMissingBuiltins/main.swift | 191 +- Sources/REPRLRun/main.swift | 16 +- Sources/RelateTool/main.swift | 7 +- Tests/FuzzilliTests/AnalyzerTest.swift | 94 +- Tests/FuzzilliTests/CompilerTests.swift | 24 +- Tests/FuzzilliTests/ContextGraphTest.swift | 19 +- .../CrashingInstrumentationMutator.swift | 9 +- Tests/FuzzilliTests/DiffOracleTests.swift | 575 +-- Tests/FuzzilliTests/EngineTests.swift | 7 +- Tests/FuzzilliTests/EnvironmentTest.swift | 34 +- Tests/FuzzilliTests/JSTyperTests.swift | 948 ++-- Tests/FuzzilliTests/Leb128Test.swift | 5 +- Tests/FuzzilliTests/LifterTest.swift | 2810 ++++++----- Tests/FuzzilliTests/LiveTests.swift | 92 +- Tests/FuzzilliTests/MinimizerTest.swift | 505 +- Tests/FuzzilliTests/MutatorTests.swift | 9 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 776 +-- .../ProgramSerializationTest.swift | 15 +- Tests/FuzzilliTests/RingBufferTest.swift | 1 + .../RuntimeAssistedMutatorTests.swift | 44 +- Tests/FuzzilliTests/ScriptWriterTest.swift | 77 +- Tests/FuzzilliTests/TestUtils.swift | 23 +- Tests/FuzzilliTests/TypeSystemTest.swift | 722 ++- Tests/FuzzilliTests/VariableMapTest.swift | 11 +- Tests/FuzzilliTests/VariableSetTest.swift | 2 +- Tests/FuzzilliTests/WasmAtomicsTests.swift | 235 +- Tests/FuzzilliTests/WasmTableTests.swift | 4 +- Tests/FuzzilliTests/WasmTests.swift | 4436 +++++++++++------ 134 files changed, 20842 insertions(+), 13162 deletions(-) diff --git a/Package.swift b/Package.swift index c7f6c90f0..e19a9dbee 100644 --- a/Package.swift +++ b/Package.swift @@ -19,10 +19,10 @@ import PackageDescription let package = Package( name: "Fuzzilli", platforms: [ - .macOS(.v13), + .macOS(.v13) ], products: [ - .library(name: "Fuzzilli",targets: ["Fuzzilli"]), + .library(name: "Fuzzilli", targets: ["Fuzzilli"]) ], dependencies: [ // We use an exact version here as we also use this version to generate the .pb.swift to @@ -31,62 +31,74 @@ let package = Package( // regenerated, whenever the version is bumped. .package(url: "https://github.com/apple/swift-protobuf.git", exact: "1.35.0"), .package( - url: "https://github.com/apple/swift-collections.git", - .upToNextMinor(from: "1.2.0") + url: "https://github.com/apple/swift-collections.git", + .upToNextMinor(from: "1.2.0") ), ], targets: [ - .target(name: "libsocket", - dependencies: []), + .target( + name: "libsocket", + dependencies: []), - .target(name: "libreprl", - dependencies: []), + .target( + name: "libreprl", + dependencies: []), - .target(name: "libcoverage", - dependencies: [], - cSettings: [.unsafeFlags(["-O3"])], // Using '-c release' when building uses '-O2', so '-O3' provides a performance gain - linkerSettings: [.linkedLibrary("rt", .when(platforms: [.linux]))]), + .target( + name: "libcoverage", + dependencies: [], + cSettings: [.unsafeFlags(["-O3"])], // Using '-c release' when building uses '-O2', so '-O3' provides a performance gain + linkerSettings: [.linkedLibrary("rt", .when(platforms: [.linux]))]), - .target(name: "Fuzzilli", - dependencies: [ - .product(name: "SwiftProtobuf", package: "swift-protobuf"), - .product(name: "Collections", package: "swift-collections"), - "libsocket", - "libreprl", - "libcoverage"], - exclude: [ - "Protobuf/operations.proto", - "Protobuf/program.proto", - "Protobuf/sync.proto", - "Protobuf/README.md", - "Protobuf/gen_programproto.py"], - resources: [ - // The ast.proto file is required by the node.js parser - .copy("Protobuf/ast.proto"), - .copy("Compiler/Parser")]), + .target( + name: "Fuzzilli", + dependencies: [ + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + .product(name: "Collections", package: "swift-collections"), + "libsocket", + "libreprl", + "libcoverage", + ], + exclude: [ + "Protobuf/operations.proto", + "Protobuf/program.proto", + "Protobuf/sync.proto", + "Protobuf/README.md", + "Protobuf/gen_programproto.py", + ], + resources: [ + // The ast.proto file is required by the node.js parser + .copy("Protobuf/ast.proto"), + .copy("Compiler/Parser"), + ]), - .executableTarget(name: "REPRLRun", - dependencies: ["libreprl"]), + .executableTarget( + name: "REPRLRun", + dependencies: ["libreprl"]), - .executableTarget(name: "FuzzilliCli", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "FuzzilliCli", + dependencies: ["Fuzzilli"]), - .executableTarget(name: "FuzzILTool", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "FuzzILTool", + dependencies: ["Fuzzilli"]), // Tool that runs d8 in Dumpling mode. First time it runs with Maglev // and Turbofan. Second time without. In both runs frames are dumped // in certain points to the files. The dumps are later compared for // equality. If they are not equal, it means that there's likely a bug // in V8. - .executableTarget(name: "RelateTool", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "RelateTool", + dependencies: ["Fuzzilli"]), .executableTarget(name: "FuzzilliDetectMissingBuiltins", dependencies: ["Fuzzilli"]), - .testTarget(name: "FuzzilliTests", - dependencies: ["Fuzzilli"], - resources: [.copy("CompilerTests")]), + .testTarget( + name: "FuzzilliTests", + dependencies: ["Fuzzilli"], + resources: [.copy("CompilerTests")]), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/FuzzILTool/main.swift b/Sources/FuzzILTool/main.swift index 3843dbc1f..bc1495653 100644 --- a/Sources/FuzzILTool/main.swift +++ b/Sources/FuzzILTool/main.swift @@ -33,7 +33,7 @@ func loadProgram(from path: String) throws -> Program { func loadAllPrograms(in dirPath: String) -> [(filename: String, program: Program)] { var isDir: ObjCBool = false - if !FileManager.default.fileExists(atPath: dirPath, isDirectory:&isDir) || !isDir.boolValue { + if !FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) || !isDir.boolValue { print("\(dirPath) is not a directory!") exit(-1) } @@ -56,7 +56,7 @@ func loadAllPrograms(in dirPath: String) -> [(filename: String, program: Program } // Takes a program and lifts it to JavaScript. -func liftToJS(_ jsLifter: JavaScriptLifter,_ prog: Program) -> String { +func liftToJS(_ jsLifter: JavaScriptLifter, _ prog: Program) -> String { let res = jsLifter.lift(prog) return res.trimmingCharacters(in: .whitespacesAndNewlines) } @@ -72,10 +72,13 @@ func liftToFuzzIL(_ prog: Program) -> String { func liftAllPrograms(in dirPath: String, with lifter: Lifter, fileExtension: String) -> Int { var numLiftedPrograms = 0 for (filename, program) in loadAllPrograms(in: dirPath) { - let newFilePath = "\(dirPath)/\(filename.dropLast(protoBufFileExtension.count))\(fileExtension)" + let newFilePath = + "\(dirPath)/\(filename.dropLast(protoBufFileExtension.count))\(fileExtension)" let content = lifter.lift(program) do { - try content.write(to: URL(fileURLWithPath: newFilePath), atomically: false, encoding: String.Encoding.utf8) + try content.write( + to: URL(fileURLWithPath: newFilePath), atomically: false, + encoding: String.Encoding.utf8) numLiftedPrograms += 1 } catch { print("Failed to write file \(newFilePath): \(error)") @@ -96,29 +99,32 @@ func loadProgramOrExit(from path: String) -> Program { let args = Arguments.parse(from: CommandLine.arguments) if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != 1 { - print(""" - Usage: - \(args.programName) options path - - Options: - --liftToFuzzIL : Lifts the given protobuf program to FuzzIL's text format and prints it - --liftToJS : Lifts the given protobuf program to JS and prints it - --liftCorpusToJS : Loads all .fzil files in a directory and lifts them to .js files in that same directory - --dumpProtobuf : Dumps the raw content of the given protobuf file - --dumpProgram : Dumps the internal representation of the program stored in the given protobuf file - --checkCorpus : Attempts to load all .fzil files in a directory and checks if they are statically valid - --compile : Compile the given JavaScript program to a FuzzIL program. Requires node.js - --outputPathJS : If given, --compile will write the lifted JS file to the given path after compilation. - --generate : Generate a random program using Fuzzilli's code generators and save it to the specified path. - --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. - """) + print( + """ + Usage: + \(args.programName) options path + + Options: + --liftToFuzzIL : Lifts the given protobuf program to FuzzIL's text format and prints it + --liftToJS : Lifts the given protobuf program to JS and prints it + --liftCorpusToJS : Loads all .fzil files in a directory and lifts them to .js files in that same directory + --dumpProtobuf : Dumps the raw content of the given protobuf file + --dumpProgram : Dumps the internal representation of the program stored in the given protobuf file + --checkCorpus : Attempts to load all .fzil files in a directory and checks if they are statically valid + --compile : Compile the given JavaScript program to a FuzzIL program. Requires node.js + --outputPathJS : If given, --compile will write the lifted JS file to the given path after compilation. + --generate : Generate a random program using Fuzzilli's code generators and save it to the specified path. + --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + """) exit(0) } let path = args[0] let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") -let jsLifter = JavaScriptLifter(prefix: jsPrefix, suffix: jsSuffix, ecmaVersion: ECMAScriptVersion.es6, environment: JavaScriptEnvironment(), alwaysEmitVariables: forDifferentialFuzzing) +let jsLifter = JavaScriptLifter( + prefix: jsPrefix, suffix: jsSuffix, ecmaVersion: ECMAScriptVersion.es6, + environment: JavaScriptEnvironment(), alwaysEmitVariables: forDifferentialFuzzing) // Covert a single IL protobuf file to FuzzIL's text format and print to stdout if args.has("--liftToFuzzIL") { @@ -134,7 +140,8 @@ else if args.has("--liftToJS") { // Lift all protobuf programs to JavaScript else if args.has("--liftCorpusToJS") { - let numLiftedPrograms = liftAllPrograms(in: path, with: jsLifter, fileExtension: jsFileExtension) + let numLiftedPrograms = liftAllPrograms( + in: path, with: jsLifter, fileExtension: jsFileExtension) print("Lifted \(numLiftedPrograms) programs to JS") } @@ -166,7 +173,9 @@ else if args.has("--compile") { exit(-1) } guard let parser = JavaScriptParser(executor: nodejs) else { - print("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for instructions on how to set it up.") + print( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for instructions on how to set it up." + ) exit(-1) } @@ -194,7 +203,9 @@ else if args.has("--compile") { if let js_path = args["--outputPathJS"] { let content = ast.leadingComments + jsLifter.lift(program) do { - try content.write(to: URL(fileURLWithPath: js_path), atomically: false, encoding: String.Encoding.utf8) + try content.write( + to: URL(fileURLWithPath: js_path), atomically: false, encoding: String.Encoding.utf8 + ) } catch { print("Failed to write file \(js_path): \(error)") exit(-1) @@ -205,7 +216,8 @@ else if args.has("--compile") { print(jsLifter.lift(program)) do { - let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension("fzil") + let outputPath = URL(fileURLWithPath: path).deletingPathExtension() + .appendingPathExtension("fzil") try program.asProtobuf().serializedData().write(to: outputPath) print("FuzzIL program written to \(outputPath.relativePath)") } catch { @@ -216,7 +228,9 @@ else if args.has("--compile") { } else if args.has("--generate") { - let fuzzer = makeMockFuzzer(config: Configuration(logLevel: .warning, enableInspection: true), environment: JavaScriptEnvironment()) + let fuzzer = makeMockFuzzer( + config: Configuration(logLevel: .warning, enableInspection: true), + environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() b.buildPrefix() b.build(n: 50, by: .generating) @@ -225,7 +239,8 @@ else if args.has("--generate") { print(jsLifter.lift(program, withOptions: .includeComments)) do { - let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension("fzil") + let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension( + "fzil") try program.asProtobuf().serializedData().write(to: outputPath) } catch { print("Failed to store output program to disk: \(error)") diff --git a/Sources/Fuzzilli/Base/ContextGraph.swift b/Sources/Fuzzilli/Base/ContextGraph.swift index 153f76541..722801e64 100644 --- a/Sources/Fuzzilli/Base/ContextGraph.swift +++ b/Sources/Fuzzilli/Base/ContextGraph.swift @@ -79,20 +79,25 @@ public class ContextGraph { for i in 1.., withLogger logger: Logger) { + private func warnOfSuspiciousContexts( + in generators: WeightedList, withLogger logger: Logger + ) { // Technically we don't need any generator to emit the .javascript context, as this is provided by the toplevel. var providedContexts = Set([.javascript]) var requiredContexts = Set() @@ -107,7 +112,9 @@ public class ContextGraph { for generator in generators { // Now check which generators don't have providers if !providedContexts.contains(generator.requiredContext) { - logger.warning("Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context.") + logger.warning( + "Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context." + ) } @@ -115,7 +122,9 @@ public class ContextGraph { if !generator.providedContexts.allSatisfy({ requiredContexts.contains($0) }) { - logger.warning("Generator \(generator.name) provides a context that is never required by another generator \(generator.providedContexts)") + logger.warning( + "Generator \(generator.name) provides a context that is never required by another generator \(generator.providedContexts)" + ) } } } @@ -139,7 +148,8 @@ public class ContextGraph { } // Get all possible edges from here on and push all of those to the queue. - for edge in self.edges where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { + for edge in self.edges + where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { // Prevent cycles, we don't care about complicated paths, but rather simple direct paths. seenNodes.insert(edge.key.to) queue.append(currentPath + [edge.key.to]) @@ -155,7 +165,7 @@ public class ContextGraph { for path in paths { var edgePath: [EdgeKey] = [] for i in 0..<(path.count - 1) { - let edge = EdgeKey(from: path[i], to: path[i+1]) + let edge = EdgeKey(from: path[i], to: path[i + 1]) edgePath.append(edge) } edgePaths.append(edgePath) @@ -185,7 +195,8 @@ public class ContextGraph { var stillExploring = false // Get all possible edges from here on and push all of those to the queue. - for edge in self.edges where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { + for edge in self.edges + where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { // Prevent cycles, we don't care about complicated paths, but rather simple direct paths. stillExploring = true seenNodes.insert(edge.key.to) @@ -220,9 +231,10 @@ public class ContextGraph { } return paths.map { edges in - Path(edges: edges.map { edge in - self.edges[edge]! - }) + Path( + edges: edges.map { edge in + self.edges[edge]! + }) } } } diff --git a/Sources/Fuzzilli/Base/Contributor.swift b/Sources/Fuzzilli/Base/Contributor.swift index 87b668464..b087363d1 100644 --- a/Sources/Fuzzilli/Base/Contributor.swift +++ b/Sources/Fuzzilli/Base/Contributor.swift @@ -93,7 +93,8 @@ public class Contributor: Hashable { } public var totalSamples: Int { - return validSamples + interestingSamples + invalidSamples + timedOutSamples + crashingSamples + differentialSamples + return validSamples + interestingSamples + invalidSamples + timedOutSamples + + crashingSamples + differentialSamples } // If this is low, that means the CodeGenerator has dynamic requirements that are not met most of the time. diff --git a/Sources/Fuzzilli/Base/Events.swift b/Sources/Fuzzilli/Base/Events.swift index 84a6832ec..f353f58ab 100644 --- a/Sources/Fuzzilli/Base/Events.swift +++ b/Sources/Fuzzilli/Base/Events.swift @@ -53,10 +53,14 @@ public class Events { public let InvalidProgramFound = Event() /// Signals that a crashing program has been found. Dispatched after the crashing program has been minimized. - public let CrashFound = Event<(program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin)>() + public let CrashFound = Event< + (program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin) + >() /// Signals that a differential program was found. Dispatched after the differential program has been minimized. - public let DifferentialFound = Event<(program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin)>() + public let DifferentialFound = Event< + (program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin) + >() /// Signals that a program causing a timeout has been found. public let TimeOutFound = Event() @@ -94,7 +98,7 @@ public class Events { /// Crash behavior of a program. public enum CrashBehaviour: String { case deterministic = "deterministic" - case flaky = "flaky" + case flaky = "flaky" } /// Reasons for shutting down a fuzzer instance. diff --git a/Sources/Fuzzilli/Base/Logging.swift b/Sources/Fuzzilli/Base/Logging.swift index abbff0cb4..307fc6c95 100644 --- a/Sources/Fuzzilli/Base/Logging.swift +++ b/Sources/Fuzzilli/Base/Logging.swift @@ -16,10 +16,10 @@ import Foundation public enum LogLevel: Int { case verbose = 0 - case info = 1 + case info = 1 case warning = 2 - case error = 3 - case fatal = 4 + case error = 3 + case fatal = 4 public func isAtLeast(_ level: LogLevel) -> Bool { return self.rawValue <= level.rawValue diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 657fec431..631f5a3f9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -24,7 +24,7 @@ public class ProgramBuilder { /// code generator. It is strictly required that all pushed values are also popped again in the /// same code generator. public class GeneratorRuntimeData { - private var data = [String : Stack]() + private var data = [String: Stack]() public func push(_ key: String, _ value: Variable) { data[key, default: .init()].push(value) @@ -44,9 +44,9 @@ public class ProgramBuilder { func reset() { #if DEBUG - for (key, value) in data { - assert(value.isEmpty, "Stale entries for runtime data '\(key)'") - } + for (key, value) in data { + assert(value.isEmpty, "Stale entries for runtime data '\(key)'") + } #endif data.removeAll(keepingCapacity: false) } @@ -197,7 +197,7 @@ public class ProgramBuilder { self.jsTyper = JSTyper(for: fuzzer.environment) self.parent = parent - if fuzzer.config.logLevel.isAtLeast(.verbose) { + if fuzzer.config.logLevel.isAtLeast(.verbose) { self.buildLog = BuildLog() } } @@ -228,7 +228,8 @@ public class ProgramBuilder { /// Finalizes and returns the constructed program, then resets this builder so it can be reused for building another program. public func finalize() -> Program { assert(scheduled.isEmpty) - let program = Program(code: code, parent: parent, comments: comments, contributors: contributors) + let program = Program( + code: code, parent: parent, comments: comments, contributors: contributors) reset() return program } @@ -290,39 +291,47 @@ public class ProgramBuilder { if probability(0.5) { return chooseUniform(from: self.fuzzer.environment.interestingIntegers) } else { - return withEqualProbability({ - Int64.random(in: -0x10...0x10) - }, { - Int64.random(in: -0x10000...0x10000) - }, { - Int64.random(in: Int64(Int32.min)...Int64(Int32.max)) - }) + return withEqualProbability( + { + Int64.random(in: -0x10...0x10) + }, + { + Int64.random(in: -0x10000...0x10000) + }, + { + Int64.random(in: Int64(Int32.min)...Int64(Int32.max)) + }) } } /// Returns a random integer value suitable as size of for example an array. /// The returned value is guaranteed to be positive. - public func randomSize(upTo maximum: Int64 = 0x100000000) -> Int64 { + public func randomSize(upTo maximum: Int64 = 0x1_0000_0000) -> Int64 { assert(maximum >= 0) if maximum < 0x1000 { return Int64.random(in: 0...maximum) } else if probability(0.5) { - return chooseUniform(from: fuzzer.environment.interestingIntegers.filter({ $0 >= 0 && $0 <= maximum })) + return chooseUniform( + from: fuzzer.environment.interestingIntegers.filter({ $0 >= 0 && $0 <= maximum })) } else { - return withEqualProbability({ - Int64.random(in: 0...0x10) - }, { - Int64.random(in: 0...0x100) - }, { - Int64.random(in: 0...0x1000) - }, { - Int64.random(in: 0...maximum) - }) + return withEqualProbability( + { + Int64.random(in: 0...0x10) + }, + { + Int64.random(in: 0...0x100) + }, + { + Int64.random(in: 0...0x1000) + }, + { + Int64.random(in: 0...maximum) + }) } } /// Returns a random non-negative integer value suitable as index. - public func randomNonNegativeIndex(upTo max: Int64 = 0x100000000) -> Int64 { + public func randomNonNegativeIndex(upTo max: Int64 = 0x1_0000_0000) -> Int64 { // Prefer small indices. if max > 10 && probability(0.33) { return Int64.random(in: 0...10) @@ -346,51 +355,61 @@ public class ProgramBuilder { if probability(0.5) { return chooseUniform(from: fuzzer.environment.interestingFloats) } else { - return withEqualProbability({ - Double.random(in: 0.0...1.0) - }, { - Double.random(in: -10.0...10.0) - }, { - Double.random(in: -1000.0...1000.0) - }, { - Double.random(in: -1000000.0...1000000.0) - }, { - // We cannot do Double.random(in: -Double.greatestFiniteMagnitude...Double.greatestFiniteMagnitude) here, - // presumably because that range is larger than what doubles can represent? So split the range in two. - if probability(0.5) { - return Double.random(in: -Double.greatestFiniteMagnitude...0) - } else { - return Double.random(in: 0...Double.greatestFiniteMagnitude) - } - }) + return withEqualProbability( + { + Double.random(in: 0.0...1.0) + }, + { + Double.random(in: -10.0...10.0) + }, + { + Double.random(in: -1000.0...1000.0) + }, + { + Double.random(in: -1000000.0...1000000.0) + }, + { + // We cannot do Double.random(in: -Double.greatestFiniteMagnitude...Double.greatestFiniteMagnitude) here, + // presumably because that range is larger than what doubles can represent? So split the range in two. + if probability(0.5) { + return Double.random(in: -Double.greatestFiniteMagnitude...0) + } else { + return Double.random(in: 0...Double.greatestFiniteMagnitude) + } + }) } } /// Returns a random string value. public func randomString() -> String { - return withEqualProbability({ - self.randomPropertyName() - }, { - self.randomMethodName() - }, { - chooseUniform(from: self.fuzzer.environment.interestingStrings) - }, { - String(self.randomInt()) - }, { - // Prefer smaller strings both for readability as well as for small string optimizations - // (e.g. optimizations for single character strings) but also generate larger strings - // to hit cons string ("rope" / concatenated string) cases. - String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) - }) + return withEqualProbability( + { + self.randomPropertyName() + }, + { + self.randomMethodName() + }, + { + chooseUniform(from: self.fuzzer.environment.interestingStrings) + }, + { + String(self.randomInt()) + }, + { + // Prefer smaller strings both for readability as well as for small string optimizations + // (e.g. optimizations for single character strings) but also generate larger strings + // to hit cons string ("rope" / concatenated string) cases. + String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) + }) } public func randomBytes() -> [UInt8] { let size = withProbability(0.9) { Int.random(in: 0...127) } else: { - Int.random(in:128...1024) + Int.random(in: 128...1024) } - return (0.. String { @@ -398,13 +417,17 @@ public class ProgramBuilder { var regex = "" let desiredLength = Int.random(in: 1...4) while regex.count < desiredLength { - regex += withEqualProbability({ - String.random(ofLength: 1) - }, { - // Pick from the available RegExp pattern, based on flags. - let candidates = self.fuzzer.environment.interestingRegExps.filter({ pattern, incompatibleFlags in flags.isDisjoint(with: incompatibleFlags) }) - return chooseUniform(from: candidates).pattern - }) + regex += withEqualProbability( + { + String.random(ofLength: 1) + }, + { + // Pick from the available RegExp pattern, based on flags. + let candidates = self.fuzzer.environment.interestingRegExps.filter({ + pattern, incompatibleFlags in flags.isDisjoint(with: incompatibleFlags) + }) + return chooseUniform(from: candidates).pattern + }) } // Now optionally concatenate with another regexp @@ -413,21 +436,25 @@ public class ProgramBuilder { } // Or add a quantifier, if there is not already a quantifier in the last position. - if probability(0.2) && !self.fuzzer.environment.interestingRegExpQuantifiers.contains(String(regex.last!)) { + if probability(0.2) + && !self.fuzzer.environment.interestingRegExpQuantifiers.contains(String(regex.last!)) + { regex += chooseUniform(from: self.fuzzer.environment.interestingRegExpQuantifiers) } // Or wrap in brackets if probability(0.1) { - withEqualProbability({ - // optionally invert the character set - if probability(0.2) { - regex = "^" + regex - } - regex = "[" + regex + "]" - }, { - regex = "(" + regex + ")" - }) + withEqualProbability( + { + // optionally invert the character set + if probability(0.2) { + regex = "^" + regex + } + regex = "[" + regex + "]" + }, + { + regex = "(" + regex + ")" + }) } return regex } @@ -503,9 +530,10 @@ public class ProgramBuilder { } private static func generateConstrained( - _ generator: () -> T, - notIn: any Collection, - fallback: () -> T) -> T { + _ generator: () -> T, + notIn: any Collection, + fallback: () -> T + ) -> T { var result: T var attempts = 0 repeat { @@ -521,15 +549,17 @@ public class ProgramBuilder { // Generate a string not already contained in `notIn` using the provided `generator`. If it fails // repeatedly, return a random string instead. public func generateString(_ generator: () -> String, notIn: any Collection) -> String { - Self.generateConstrained(generator, notIn: notIn, - fallback: {String.random(ofLength: Int.random(in: 1...5))}) + Self.generateConstrained( + generator, notIn: notIn, + fallback: { String.random(ofLength: Int.random(in: 1...5)) }) } // Find a random variable to use as a string that isn't contained in `notIn`. If it fails // repeatedly, create a random string literal instead. public func findOrGenerateStringLikeVariable(notIn: any Collection) -> Variable { - return Self.generateConstrained(randomJsVariable, notIn: notIn, - fallback: {loadString(String.random(ofLength: Int.random(in: 1...5)))}) + return Self.generateConstrained( + randomJsVariable, notIn: notIn, + fallback: { loadString(String.random(ofLength: Int.random(in: 1...5))) }) } // Settings and constants controlling the behavior of randomParameters() below. @@ -549,8 +579,13 @@ public class ProgramBuilder { // // This will attempt to find a parameter types for which at least a few variables of a compatible types are // currently available to (potentially) later be used as arguments for calling the generated subroutine. - public func randomParameters(n wantedNumberOfParameters: Int? = nil, withRestParameterProbability restProbability: Double = 0.2) -> SubroutineDescriptor { - assert(probabilityOfUsingAnythingAsParameterTypeIfAvoidable >= 0 && probabilityOfUsingAnythingAsParameterTypeIfAvoidable <= 1) + public func randomParameters( + n wantedNumberOfParameters: Int? = nil, + withRestParameterProbability restProbability: Double = 0.2 + ) -> SubroutineDescriptor { + assert( + probabilityOfUsingAnythingAsParameterTypeIfAvoidable >= 0 + && probabilityOfUsingAnythingAsParameterTypeIfAvoidable <= 1) // If the caller didn't specify how many parameters to generated, find an appropriate // number of parameters based on how many variables are currently visible (and can @@ -580,7 +615,8 @@ public class ProgramBuilder { availableVariablesByType[t] = (availableVariablesByType[t] ?? 0) + 1 } - var candidates = Array(availableVariablesByType.filter({ k, v in v >= thresholdForUseAsParameter }).keys) + var candidates = Array( + availableVariablesByType.filter({ k, v in v >= thresholdForUseAsParameter }).keys) if candidates.isEmpty { candidates.append(.jsAnything) } @@ -611,7 +647,9 @@ public class ProgramBuilder { return .parameters(params) } - public func findOrGenerateArguments(forSignature signature: Signature, maxNumberOfVariablesToGenerate: Int = 100) -> [Variable] { + public func findOrGenerateArguments( + forSignature signature: Signature, maxNumberOfVariablesToGenerate: Int = 100 + ) -> [Variable] { assert(context.contains(.javascript)) argumentGenerationVariableBudget.push(numVariables + maxNumberOfVariablesToGenerate) @@ -650,7 +688,7 @@ public class ProgramBuilder { // This should be called whenever we have a type that has known information about its properties but we don't have a constructor for it. // This can be the case for configuration objects, e.g. objects that can be passed into DOMAPIs. - private func createObjectWithProperties(_ type: ILType) -> Variable { + private func createObjectWithProperties(_ type: ILType) -> Variable { assert(type.MayBe(.object())) // Before we do any generation below, let's take into account that we already create a variable with this invocation, i.e. the createObject at the end. @@ -670,7 +708,9 @@ public class ProgramBuilder { return createObject(with: properties) } - public func findOrGenerateType(_ type: ILType, maxNumberOfVariablesToGenerate: Int = 100) -> Variable { + public func findOrGenerateType(_ type: ILType, maxNumberOfVariablesToGenerate: Int = 100) + -> Variable + { assert(context.contains(.javascript)) argumentGenerationVariableBudget.push(numVariables + maxNumberOfVariablesToGenerate) @@ -695,7 +735,9 @@ public class ProgramBuilder { for element in path.dropFirst() { current = getProperty(element, of: current) } - assert(self.type(of: current).Is(type), "Registered constructorPath produces incorrect type for ObjectGroup \(group)") + assert( + self.type(of: current).Is(type), + "Registered constructorPath produces incorrect type for ObjectGroup \(group)") return current } @@ -713,9 +755,13 @@ public class ProgramBuilder { if numVariables >= argumentGenerationVariableBudget.top { if !argumentGenerationSignature.isEmpty { - logger.warning("Reached variable generation limit in generateType for Signature: \(argumentGenerationSignature.top), returning a random variable for use as type \(type).") + logger.warning( + "Reached variable generation limit in generateType for Signature: \(argumentGenerationSignature.top), returning a random variable for use as type \(type)." + ) } else { - logger.warning("Reached variable generation limit in generateType, returning a random variable for use as type \(type).") + logger.warning( + "Reached variable generation limit in generateType, returning a random variable for use as type \(type)." + ) } return randomVariable(forUseAs: type) } @@ -724,78 +770,121 @@ public class ProgramBuilder { // TODO: Not sure how we should handle merge types, e.g. .string + .object(...). let typeGenerators: [(ILType, () -> Variable)] = [ (.integer, { return self.loadInt(self.randomInt()) }), - (.string, { - if type.isEnumeration { - return self.loadEnum(type) - } - if let typeName = type.group, - let customStringGen = self.fuzzer.environment.getNamedStringGenerator(ofName: typeName) { - return self.loadString(customStringGen(), customName: typeName) + ( + .string, + { + if type.isEnumeration { + return self.loadEnum(type) + } + if let typeName = type.group, + let customStringGen = self.fuzzer.environment.getNamedStringGenerator( + ofName: typeName) + { + return self.loadString(customStringGen(), customName: typeName) + } + return self.loadString(self.randomString()) } - return self.loadString(self.randomString()) }), + ), (.boolean, { return self.loadBool(probability(0.5)) }), (.bigint, { return self.loadBigInt(self.randomInt()) }), (.float, { return self.loadFloat(self.randomFloat()) }), - (.regexp, { + ( + .regexp, + { let (pattern, flags) = self.randomRegExpPatternAndFlags() return self.loadRegExp(pattern, flags) - }), + } + ), (.iterable, { return self.createArray(with: [self.randomJsVariable()]) }), - (.function(), { + ( + .function(), + { // TODO: We could technically generate a full function here but then we would enter the full code generation logic which could do anything. // Because we want to avoid this, we will just pick anything that can be a function. // // Note that builtin constructors are handled above in the maybeGenerateConstructorAsPath call. return self.randomVariable(forUseAs: .function()) - }), - (.unboundFunction(), { - // TODO: We have the same issue as above for functions. - // First try to find an existing unbound function. if not present, try to find any - // function. Using any function as an unbound function is fine, it just misses the - // information about the receiver type (which for many functions doesn't matter). - return self.randomVariable(ofType: .unboundFunction()) ?? self.randomVariable(forUseAs: .function()) - }), + } + ), + ( + .unboundFunction(), + { + // TODO: We have the same issue as above for functions. + // First try to find an existing unbound function. if not present, try to find any + // function. Using any function as an unbound function is fine, it just misses the + // information about the receiver type (which for many functions doesn't matter). + return self.randomVariable(ofType: .unboundFunction()) + ?? self.randomVariable(forUseAs: .function()) + } + ), (.undefined, { return self.loadUndefined() }), - (.constructor(), { + ( + .constructor(), + { // TODO: We have the same issue as above for functions. // // Note that builtin constructors are handled above in the maybeGenerateConstructorAsPath call. return self.randomVariable(forUseAs: .constructor()) - }), - (.wasmTypeDef(), { - // Call into the WasmTypeGroup generator (or other that provide a .wasmTypeDef) - let generators = self.fuzzer.codeGenerators.filter { gen in - gen.produces.contains { produces in - produces.type.Is(.wasmTypeDef()) - } } - let _ = self.complete(generator: generators.randomElement(), withBudget: 5) - return self.randomVariable(ofType: .wasmTypeDef())! - }), - (.object(), { - func useMethodToProduce(_ method: (group: String, method: String)) -> Variable { - let group = self.fuzzer.environment.type(ofGroup: method.group) - let obj = self.generateTypeInternal(group) - let sig = chooseUniform( - from: self.fuzzer.environment - .signatures(ofMethod: method.method, on: group).filter({ - self.fuzzer.environment.isSubtype($0.outputType, of: type) - })) - - let args = self.findOrGenerateArgumentsInternal(forSignature: sig) - return self.callMethod(method.method, on: obj, withArgs: args) + ), + ( + .wasmTypeDef(), + { + // Call into the WasmTypeGroup generator (or other that provide a .wasmTypeDef) + let generators = self.fuzzer.codeGenerators.filter { gen in + gen.produces.contains { produces in + produces.type.Is(.wasmTypeDef()) + } + } + let _ = self.complete(generator: generators.randomElement(), withBudget: 5) + return self.randomVariable(ofType: .wasmTypeDef())! } + ), + ( + .object(), + { + func useMethodToProduce(_ method: (group: String, method: String)) -> Variable { + let group = self.fuzzer.environment.type(ofGroup: method.group) + let obj = self.generateTypeInternal(group) + let sig = chooseUniform( + from: self.fuzzer.environment + .signatures(ofMethod: method.method, on: group).filter({ + self.fuzzer.environment.isSubtype($0.outputType, of: type) + })) + + let args = self.findOrGenerateArgumentsInternal(forSignature: sig) + return self.callMethod(method.method, on: obj, withArgs: args) + } - func usePropertyToProduce(_ property: (group: String, property: String)) -> Variable { - // If no ObjectGroup is defined, the property is a builtin. - if property.group == "" { - let builtinType = self.fuzzer.environment.type(ofBuiltin: property.property) - let prop = self.createNamedVariable(forBuiltin: property.property) - if builtinType.Is(type) { + func usePropertyToProduce(_ property: (group: String, property: String)) + -> Variable + { + // If no ObjectGroup is defined, the property is a builtin. + if property.group == "" { + let builtinType = self.fuzzer.environment.type( + ofBuiltin: property.property) + let prop = self.createNamedVariable(forBuiltin: property.property) + if builtinType.Is(type) { + return prop + } else { + // This is a constructor, we have to call it. + let sig = builtinType.signature + if sig == nil { + let result = self.randomJsVariable() + return result + } + let args = self.findOrGenerateArgumentsInternal(forSignature: sig!) + return self.construct(prop, withArgs: args) + } + } + let group = self.fuzzer.environment.type(ofGroup: property.group) + let obj = self.generateTypeInternal(group) + let prop = self.getProperty(property.property, of: obj) + if self.type(of: prop).Is(type) { return prop } else { // This is a constructor, we have to call it. - let sig = builtinType.signature + let sig = self.type(of: prop).signature if sig == nil { let result = self.randomJsVariable() return result @@ -804,78 +893,70 @@ public class ProgramBuilder { return self.construct(prop, withArgs: args) } } - let group = self.fuzzer.environment.type(ofGroup: property.group) - let obj = self.generateTypeInternal(group) - let prop = self.getProperty(property.property, of: obj) - if self.type(of: prop).Is(type) { - return prop - } else { - // This is a constructor, we have to call it. - let sig = self.type(of: prop).signature - if sig == nil { - let result = self.randomJsVariable() - return result + + // If we have a producing generator, we aren't going to get this type from elsewhere + // so try and generate it using the generator in most cases + let producingGenerator = self.fuzzer.environment.getProducingGenerator( + ofType: type) + if let producingGenerator { + if probability(producingGenerator.probability) { + return producingGenerator.generator(self) } - let args = self.findOrGenerateArgumentsInternal(forSignature: sig!) - return self.construct(prop, withArgs: args) } - } - // If we have a producing generator, we aren't going to get this type from elsewhere - // so try and generate it using the generator in most cases - let producingGenerator = self.fuzzer.environment.getProducingGenerator(ofType: type); - if let producingGenerator { - if probability(producingGenerator.probability) { - return producingGenerator.generator(self) + let producingMethods = self.fuzzer.environment.getProducingMethods(ofType: type) + let producingProperties = self.fuzzer.environment.getProducingProperties( + ofType: type) + let globalProperties = producingProperties.filter { + (group: String, property: String) in + // Global properties are those that don't belong to a group, i.e. where the group is empty. + return group == "" } - } - - let producingMethods = self.fuzzer.environment.getProducingMethods(ofType: type) - let producingProperties = self.fuzzer.environment.getProducingProperties(ofType: type) - let globalProperties = producingProperties.filter() {(group: String, property: String) in - // Global properties are those that don't belong to a group, i.e. where the group is empty. - return group == "" - } - // If there is a global property or builtin for this type, use it with high probability. - if !globalProperties.isEmpty && probability(0.9) { - return usePropertyToProduce(globalProperties.randomElement()!) - } - let maybeMethod = producingMethods.randomElement() - let maybeProperty = producingProperties.randomElement() - if let method = maybeMethod ,let property = maybeProperty { - if probability(Double(producingMethods.count) / Double(producingMethods.count + producingProperties.count)) { + // If there is a global property or builtin for this type, use it with high probability. + if !globalProperties.isEmpty && probability(0.9) { + return usePropertyToProduce(globalProperties.randomElement()!) + } + let maybeMethod = producingMethods.randomElement() + let maybeProperty = producingProperties.randomElement() + if let method = maybeMethod, let property = maybeProperty { + if probability( + Double(producingMethods.count) + / Double(producingMethods.count + producingProperties.count)) + { + return useMethodToProduce(method) + } else { + return usePropertyToProduce(property) + } + } else if let method = maybeMethod { return useMethodToProduce(method) - } else { + } else if let property = maybeProperty { return usePropertyToProduce(property) } - } else if let method = maybeMethod { - return useMethodToProduce(method) - } else if let property = maybeProperty { - return usePropertyToProduce(property) - } - let generators = self.fuzzer.codeGenerators.filter({ - // Right now only use generators that require a single context. - $0.parts.last!.requiredContext.isSingle && - $0.parts.last!.requiredContext.satisfied(by: self.context) && - $0.parts.last!.produces.contains(where: { produces in - produces.type.Is(type) + let generators = self.fuzzer.codeGenerators.filter({ + // Right now only use generators that require a single context. + $0.parts.last!.requiredContext.isSingle + && $0.parts.last!.requiredContext.satisfied(by: self.context) + && $0.parts.last!.produces.contains(where: { produces in + produces.type.Is(type) + }) }) - }) - if generators.count > 0 { - let generator = generators.randomElement() - let _ = self.complete(generator: generator, withBudget: 10) - guard let variable = self.randomVariable(ofTypeOrSubtype: type) else { - fatalError("The generator \(generator.name) is supposed to generate type " + - "\(type). Either the generator or its annotation is wrong.") + if generators.count > 0 { + let generator = generators.randomElement() + let _ = self.complete(generator: generator, withBudget: 10) + guard let variable = self.randomVariable(ofTypeOrSubtype: type) else { + fatalError( + "The generator \(generator.name) is supposed to generate type " + + "\(type). Either the generator or its annotation is wrong.") + } + return variable } - return variable + // Otherwise this is one of the following: + // 1. an object with more type information, i.e. it has a group, but no associated builtin, e.g. we cannot construct it with new. + // 2. an object without a group, but it has some required fields. + // In either case, we try to construct such an object. + return self.createObjectWithProperties(type) } - // Otherwise this is one of the following: - // 1. an object with more type information, i.e. it has a group, but no associated builtin, e.g. we cannot construct it with new. - // 2. an object without a group, but it has some required fields. - // In either case, we try to construct such an object. - return self.createObjectWithProperties(type) - }) + ), ] // Make sure that we walk over these tests and their generators randomly. @@ -919,7 +1000,11 @@ public class ProgramBuilder { var variables = [Variable]() while variables.count < n { - guard let newVar = findVariable(satisfying: { !variables.contains($0) && type(of: $0).Is(.jsAnything) }) else { + guard + let newVar = findVariable(satisfying: { + !variables.contains($0) && type(of: $0).Is(.jsAnything) + }) + else { break } variables.append(newVar) @@ -954,7 +1039,8 @@ public class ProgramBuilder { /// is a random JsVariable. /// /// If the variable must be of the specified type, use `randomVariable(ofType:)` instead. - public func randomVariable(forUseAsGuarded type: ILType) -> (variable: Variable, matches: Bool) { + public func randomVariable(forUseAsGuarded type: ILType) -> (variable: Variable, matches: Bool) + { assert(type != .nothing) var result: Variable? = nil @@ -1000,7 +1086,7 @@ public class ProgramBuilder { public func randomVariable(ofTypeOrSubtype type: ILType) -> Variable? { assert(type != .nothing) - return findVariable() { (variable: Variable) in + return findVariable { (variable: Variable) in fuzzer.environment.isSubtype(self.type(of: variable), of: type) } } @@ -1072,7 +1158,9 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling the specified method. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingMethod methodName: String, on object: Variable) -> [Variable] { + public func randomArguments(forCallingMethod methodName: String, on object: Variable) + -> [Variable] + { let signature = chooseUniform(from: methodSignatures(of: methodName, on: object)) return randomArguments(forCallingFunctionWithSignature: signature) } @@ -1080,7 +1168,9 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling the specified method. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingMethod methodName: String, on objType: ILType) -> [Variable] { + public func randomArguments(forCallingMethod methodName: String, on objType: ILType) + -> [Variable] + { let signature = chooseUniform(from: methodSignatures(of: methodName, on: objType)) return randomArguments(forCallingFunctionWithSignature: signature) } @@ -1088,14 +1178,17 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling a function with the specified signature. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingFunctionWithSignature signature: Signature) -> [Variable] { + public func randomArguments(forCallingFunctionWithSignature signature: Signature) -> [Variable] + { return randomArguments(forCallingFunctionWithParameters: signature.parameters) } /// Find random variables to use as arguments for calling a function with the given parameters. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingFunctionWithParameters params: ParameterList) -> [Variable] { + public func randomArguments(forCallingFunctionWithParameters params: ParameterList) + -> [Variable] + { assert(params.count == 0 || hasVisibleVariables) let parameterTypes = ProgramBuilder.prepareArgumentTypes(forParameters: params) return parameterTypes.map({ randomVariable(forUseAs: $0) }) @@ -1105,7 +1198,9 @@ public class ProgramBuilder { /// /// If any of the arguments returned does not match the type of its corresponding parameter, /// the boolean this function returns will be true. If everything matches, it will be false. - public func randomArguments(forCallingGuardableFunction function: Variable) -> (arguments: [Variable], allArgsMatch: Bool) { + public func randomArguments(forCallingGuardableFunction function: Variable) -> ( + arguments: [Variable], allArgsMatch: Bool + ) { let signature = type(of: function).signature ?? Signature.forUnknownFunction let params = signature.parameters assert(params.count == 0 || hasVisibleVariables) @@ -1123,7 +1218,6 @@ public class ProgramBuilder { return (variables, allArgsMatch) } - /// Converts the JS world signature into a Wasm world signature. /// In practice this means that we will try to map JS types to corresponding Wasm types. /// E.g. .number becomes .wasmf32, .bigint will become .wasmi64, etc. @@ -1131,7 +1225,9 @@ public class ProgramBuilder { /// I.e. .object might be converted to .wasmf32 or .wasmExternRef. /// Use this function to generate arguments for a WasmJsCall operation and attach the converted signature to /// the WasmJsCall instruction. - public func randomWasmArguments(forCallingJsFunction function: Variable) -> (WasmSignature, [Variable])? { + public func randomWasmArguments(forCallingJsFunction function: Variable) -> ( + WasmSignature, [Variable] + )? { let signature = type(of: function).signature ?? Signature.forUnknownFunction var visibleTypes = [ILType: Int]() @@ -1157,7 +1253,8 @@ public class ProgramBuilder { } // This already does an approximation of the JS signature - let newSignature = ProgramBuilder.convertJsSignatureToWasmSignature(signature, availableTypes: weightedTypes) + let newSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + signature, availableTypes: weightedTypes) guard let variables = randomWasmArguments(forWasmSignature: newSignature) else { return nil @@ -1181,8 +1278,12 @@ public class ProgramBuilder { // We simplify the signature by first converting it into types, approximating this signature by getting the corresponding Wasm world types. // Then we convert that back into a signature with only .plain types and attach that to the WasmJsCall instruction. - public static func convertJsSignatureToWasmSignature(_ signature: Signature, availableTypes types: WeightedList) -> WasmSignature { - let parameterTypes = prepareArgumentTypes(forParameters: signature.parameters).map { approximateWasmTypeFromJsType($0, availableTypes: types) } + public static func convertJsSignatureToWasmSignature( + _ signature: Signature, availableTypes types: WeightedList + ) -> WasmSignature { + let parameterTypes = prepareArgumentTypes(forParameters: signature.parameters).map { + approximateWasmTypeFromJsType($0, availableTypes: types) + } let outputType = mapJsToWasmType(signature.outputType) return WasmSignature(expects: parameterTypes, returns: [outputType]) } @@ -1190,20 +1291,27 @@ public class ProgramBuilder { public static func convertWasmSignatureToJsSignature(_ signature: WasmSignature) -> Signature { let parameterTypes = signature.parameterTypes.map(mapWasmToJsType) // If we return multiple values it will just be an Array in JavaScript. - let returnType = signature.outputTypes.count == 0 ? ILType.undefined - : signature.outputTypes.count == 1 ? mapWasmToJsType(signature.outputTypes[0]) - : .jsArray + let returnType = + signature.outputTypes.count == 0 + ? ILType.undefined + : signature.outputTypes.count == 1 + ? mapWasmToJsType(signature.outputTypes[0]) + : .jsArray return Signature(expects: parameterTypes.map(Parameter.plain), returns: returnType) } - public static func convertJsSignatureToWasmSignatureDeterministic(_ signature: Signature) -> WasmSignature { - let parameterTypes = prepareArgumentTypesDeterministic(forParameters: signature.parameters).map { mapJsToWasmType($0) } + public static func convertJsSignatureToWasmSignatureDeterministic(_ signature: Signature) + -> WasmSignature + { + let parameterTypes = prepareArgumentTypesDeterministic(forParameters: signature.parameters) + .map { mapJsToWasmType($0) } let outputType = mapJsToWasmType(signature.outputType) return WasmSignature(expects: parameterTypes, returns: [outputType]) } /// Find random arguments for a function call and spread some of them. - public func randomCallArgumentsWithSpreading(n: Int) -> (arguments: [Variable], spreads: [Bool]) { + public func randomCallArgumentsWithSpreading(n: Int) -> (arguments: [Variable], spreads: [Bool]) + { var arguments: [Variable] = [] var spreads: [Bool] = [] for _ in 0...n { @@ -1275,7 +1383,7 @@ public class ProgramBuilder { /// /// From being generated, which can happen quite frequently during prefix generation as /// the number of visible variables may be quite small. - private func bodyWithRecursionGuard(_ variableToHide: Variable, body: () -> ()) { + private func bodyWithRecursionGuard(_ variableToHide: Variable, body: () -> Void) { hide(variableToHide) body() unhide(variableToHide) @@ -1326,7 +1434,9 @@ public class ProgramBuilder { return .function() } else if type.Is(.wasmI31Ref()) { return .integer - } else if type.Is(.wasmNullRef()) || type.Is(.wasmNullExternRef()) || type.Is(.wasmNullFuncRef()) { + } else if type.Is(.wasmNullRef()) || type.Is(.wasmNullExternRef()) + || type.Is(.wasmNullFuncRef()) + { // This is slightly imprecise: The null types only accept null, not undefined but // Fuzzilli doesn't differentiate between null and undefined in its type system. return .nullish @@ -1338,10 +1448,13 @@ public class ProgramBuilder { } // Helper function to convert JS Types to an arbitrary matching Wasm type or picks from the other available types- - private static func approximateWasmTypeFromJsType(_ type: ILType, availableTypes: WeightedList) -> ILType { + private static func approximateWasmTypeFromJsType( + _ type: ILType, availableTypes: WeightedList + ) -> ILType { let matchingTypes = matchingWasmTypes(jsType: type) - let intersection = availableTypes.filter({type in matchingTypes.contains(type)}) - return intersection.count != 0 ? intersection.randomElement() : availableTypes.randomElement() + let intersection = availableTypes.filter({ type in matchingTypes.contains(type) }) + return intersection.count != 0 + ? intersection.randomElement() : availableTypes.randomElement() } /// Type information access. @@ -1407,7 +1520,9 @@ public class ProgramBuilder { return argumentTypes } - private static func prepareArgumentTypesDeterministic(forParameters params: ParameterList) -> [ILType] { + private static func prepareArgumentTypesDeterministic(forParameters params: ParameterList) + -> [ILType] + { var argumentTypes = [ILType]() for param in params { @@ -1456,7 +1571,8 @@ public class ProgramBuilder { } /// Maps a list of variables from the program that is currently configured for adoption into the program being constructed. - public func adopt(_ variables: Variables) -> [Variable] where Variables.Element == Variable { + public func adopt(_ variables: Variables) -> [Variable] + where Variables.Element == Variable { return variables.map(adopt) } @@ -1478,7 +1594,7 @@ public class ProgramBuilder { /// This also renames any variable used in the given program so all variables /// from the appended program refer to the same values in the current program. public func append(_ program: Program) { - adopting() { + adopting { for instr in program.code { adopt(instr) } @@ -1493,7 +1609,6 @@ public class ProgramBuilder { // The probability of including an instruction that may mutate a variable required by the slice (but does not itself produce a required variable). var probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable = 0.5 - /// Splice code from the given program into the current program. /// /// Splicing computes a set of dependent (through dataflow) instructions in one program (called a "slice") and inserts it at the current position in this program. @@ -1502,7 +1617,9 @@ public class ProgramBuilder { /// If mergeDataFlow is true, the dataflows of the two programs are potentially integrated by replacing some variables in the slice with "compatible" variables in the host program. /// Returns true on success (if at least one instruction has been spliced), false otherwise. @discardableResult - public func splice(from program: Program, at specifiedIndex: Int? = nil, mergeDataFlow: Bool = true) -> Bool { + public func splice( + from program: Program, at specifiedIndex: Int? = nil, mergeDataFlow: Bool = true + ) -> Bool { // Splicing: // // Invariants: @@ -1568,7 +1685,8 @@ public class ProgramBuilder { var activeBlocks = [Block]() func updateBlockDependencies(_ requiredContext: Context, _ requiredInputs: VariableSet) { guard let current = activeBlocks.last else { return } - current.requiredContext.formUnion(requiredContext.subtracting(current.currentlyOpenedContext)) + current.requiredContext.formUnion( + requiredContext.subtracting(current.currentlyOpenedContext)) current.requiredInputs.formUnion(requiredInputs.subtracting(current.providedInputs)) } func updateBlockProvidedVariables(_ vars: ArraySlice) { @@ -1629,7 +1747,9 @@ public class ProgramBuilder { // Prior to that, it is assumed to be .jsAnything. This may lead to incompatible functions being selected // as replacements (e.g. if the following code assumes that the return value must be of type X), but // is probably fine in practice. - assert(!instr.hasOneOutput || v != instr.output || !(instr.op is BeginAnySubroutine) || (type.signature?.outputType ?? .jsAnything) == .jsAnything) + assert( + !instr.hasOneOutput || v != instr.output || !(instr.op is BeginAnySubroutine) + || (type.signature?.outputType ?? .jsAnything) == .jsAnything) // Try to find a compatible variable in the host program. let replacement: Variable if let match = randomVariable(ofType: type) { @@ -1642,13 +1762,18 @@ public class ProgramBuilder { availableVariables.insert(v) } } - func maybeRemapVariables(_ variables: ArraySlice, of instr: Instruction, withProbability remapProbability: Double) { + func maybeRemapVariables( + _ variables: ArraySlice, of instr: Instruction, + withProbability remapProbability: Double + ) { assert(remapProbability >= 0.0 && remapProbability <= 1.0) if probability(remapProbability) { tryRemapVariables(variables, of: instr) } } - func getRequirements(of instr: Instruction) -> (requiredContext: Context, requiredInputs: VariableSet) { + func getRequirements(of instr: Instruction) -> ( + requiredContext: Context, requiredInputs: VariableSet + ) { if let state = blocks[instr.index] { assert(instr.isBlock) return (state.requiredContext, state.requiredInputs) @@ -1662,14 +1787,20 @@ public class ProgramBuilder { typer.analyze(instr) // Maybe remap the outputs of this instruction to existing and "compatible" (because of their type) variables in the host program. - maybeRemapVariables(instr.outputs, of: instr, withProbability: probabilityOfRemappingAnInstructionsOutputsDuringSplicing) - maybeRemapVariables(instr.innerOutputs, of: instr, withProbability: probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing) + maybeRemapVariables( + instr.outputs, of: instr, + withProbability: probabilityOfRemappingAnInstructionsOutputsDuringSplicing) + maybeRemapVariables( + instr.innerOutputs, of: instr, + withProbability: probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing) // For the purpose of this step, blocks are treated as a single instruction with all the context and input requirements of the // instructions in their body. This is done through the getRequirements function which uses the data computed in step (1). let (requiredContext, requiredInputs) = getRequirements(of: instr) - if requiredContext.isSubset(of: context) && requiredInputs.isSubset(of: availableVariables) { + if requiredContext.isSubset(of: context) + && requiredInputs.isSubset(of: availableVariables) + { candidates.insert(instr.index) // This instruction is available, and so are its outputs... availableVariables.formUnion(instr.allOutputs) @@ -1690,13 +1821,15 @@ public class ProgramBuilder { let rootCandidates = candidates.filter { (!program.code[$0].isSimple || program.code[$0].numInputs > 0 - || !program.code[$0].op.requiredContext.contains(.javascript) - ) && !(program.code[$0].op is WasmReturn) + || !program.code[$0].op.requiredContext.contains(.javascript)) + && !(program.code[$0].op is WasmReturn) } guard !rootCandidates.isEmpty else { return false } let rootIndex = specifiedIndex ?? chooseUniform(from: rootCandidates) guard rootCandidates.contains(rootIndex) else { return false } - trace("Splicing instruction \(rootIndex) (\(program.code[rootIndex].op.name)) from \(program.id)") + trace( + "Splicing instruction \(rootIndex) (\(program.code[rootIndex].op.name)) from \(program.id)" + ) // // Step (4): compute the slice. @@ -1735,7 +1868,8 @@ public class ProgramBuilder { slice.insert(instr.index) // Only those inputs that we haven't picked replacements for are now also required. - let newlyRequiredVariables = instr.inputs.filter({ !remappedVariables.contains($0) }) + let newlyRequiredVariables = instr.inputs.filter({ !remappedVariables.contains($0) } + ) requiredVariables.formUnion(newlyRequiredVariables) if !shouldIncludeCurrentBlock && instr.isBlock { @@ -1817,16 +1951,16 @@ public class ProgramBuilder { var description: String { switch self { - case .success: - return "✅" - case .failed(let reason): - if let reason { - return "❌: \(reason)" - } else { - return "❌" - } - case .started: - return "started" + case .success: + return "✅" + case .failed(let reason): + if let reason { + return "❌: \(reason)" + } else { + return "❌" + } + case .started: + return "started" } } } @@ -1856,17 +1990,19 @@ public class ProgramBuilder { finishedAction.outcome = .success actions.append((finishedAction, indent)) #if DEBUG - // Now Check that we have variables that match the the specified productions. - for requirement in finishedAction.produces { - if !newlyCreatedVariableTypes.contains(where: requirement.fulfilled) { - var fatalErrorString = "" - fatalErrorString += "Action: \(finishedAction.name)\n" - fatalErrorString += "Action guaranteed it would produce: \(finishedAction.produces)\n" - fatalErrorString += "\(getLogString())\n" - fatalErrorString += "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)" - fatalError(fatalErrorString) + // Now Check that we have variables that match the the specified productions. + for requirement in finishedAction.produces { + if !newlyCreatedVariableTypes.contains(where: requirement.fulfilled) { + var fatalErrorString = "" + fatalErrorString += "Action: \(finishedAction.name)\n" + fatalErrorString += + "Action guaranteed it would produce: \(finishedAction.produces)\n" + fatalErrorString += "\(getLogString())\n" + fatalErrorString += + "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)" + fatalError(fatalErrorString) + } } - } #endif } @@ -1887,21 +2023,22 @@ public class ProgramBuilder { } mutating func reset() { - assert(pendingActions.isEmpty, "We should have completed all pending build actions, either failed or succeeded.") + assert( + pendingActions.isEmpty, + "We should have completed all pending build actions, either failed or succeeded.") // This is basically equivalent with the statement above. assert(indent == 0) actions.removeAll() } } - // The BuildLog records all `run` and `complete` calls on this ProgramBuilder, be it through mutation or generation. #if DEBUG - // We definitely want to have the BuildLog in DEBUG builds. - var buildLog: BuildLog? = BuildLog() + // We definitely want to have the BuildLog in DEBUG builds. + var buildLog: BuildLog? = BuildLog() #else - // We initialize this depending on the LogLevel in the initializer. - var buildLog: BuildLog? = nil + // We initialize this depending on the LogLevel in the initializer. + var buildLog: BuildLog? = nil #endif /// Build random code at the current position in the program. @@ -1919,15 +2056,16 @@ public class ProgramBuilder { let splitFactor = 2 // If the corpus is empty, we have to pick generating here, this is only relevant for the first sample. - let mode: BuildingMode = if fuzzer.corpus.isEmpty { - .generating - } else { - if buildingMode == .generatingAndSplicing { - chooseUniform(from: [.generating, .splicing]) + let mode: BuildingMode = + if fuzzer.corpus.isEmpty { + .generating } else { - buildingMode + if buildingMode == .generatingAndSplicing { + chooseUniform(from: [.generating, .splicing]) + } else { + buildingMode + } } - } // Now depending on the budget we will do one of these things: // 1. Large budget is still here. Pick a scheduled CodeGenerator, or a random CodeGenerator. @@ -1947,14 +2085,19 @@ public class ProgramBuilder { let origContext = context while remainingBudget > 0 { - assert(context == origContext, "Code generation or splicing must not change the current context") + assert( + context == origContext, + "Code generation or splicing must not change the current context") let codeSizeBefore = code.count switch mode { case .generating: // This requirement might seem somewhat arbitrary but our JavaScript code generators make use of `b.randomVariable` and as such rely on the availability of // visible Variables. Therefore we should always have some Variables visible if we want to use them. - assert(hasVisibleVariables, "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program") + assert( + hasVisibleVariables, + "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program" + ) var generator: CodeGenerator? = nil @@ -1980,7 +2123,8 @@ public class ProgramBuilder { break } // Select a random CodeGenerator that is reachable from the current context and run it. - let reachableContexts = fuzzer.contextGraph.getReachableContexts(from: context) + let reachableContexts = fuzzer.contextGraph.getReachableContexts( + from: context) let possibleGenerators = fuzzer.codeGenerators.filter({ generator in reachableContexts.reduce(false) { res, reachable in return res || generator.requiredContext.isSubset(of: reachable) @@ -2076,12 +2220,16 @@ public class ProgramBuilder { // Just fully run the generator without yielding back. // Think about changing this and calling into the higher level build logic? // TODO arbitrary budget here right now, change this to some split factor? - let numberOfGeneratedInstructions = self.complete(generator: generator, withBudget: currentBudget / 5) + let numberOfGeneratedInstructions = self.complete( + generator: generator, withBudget: currentBudget / 5) assert(numberOfGeneratedInstructions > 0, "ValueGenerators must always succeed") totalNumberOfGeneratedInstructions += numberOfGeneratedInstructions } - return (totalNumberOfGeneratedInstructions, numberOfVisibleVariables - previousNumberOfVisibleVariables) + return ( + totalNumberOfGeneratedInstructions, + numberOfVisibleVariables - previousNumberOfVisibleVariables + ) } /// Bootstrap program building by creating some variables with statically known types. @@ -2118,16 +2266,19 @@ public class ProgramBuilder { let newVisibleVariables = visibleVariables.filter { v in let t = type(of: v) - return !oldVisibleVariables.contains(v) && t.wasmTypeDefinition?.description != .selfReference && t.Is(.wasmTypeDef()) + return !oldVisibleVariables.contains(v) + && t.wasmTypeDefinition?.description != .selfReference && t.Is(.wasmTypeDef()) } let newOp = WasmEndTypeGroup(typesCount: instr.inputs.count + newVisibleVariables.count) // We need to keep and adopt the inputs that are still there. let newInputs = adopt(instr.inputs) + newVisibleVariables // Adopt the old outputs and allocate new output variables for the new outputs - let newOutputs = adopt(instr.outputs) + newVisibleVariables.map { _ in - nextVariable() - } + let newOutputs = + adopt(instr.outputs) + + newVisibleVariables.map { _ in + nextVariable() + } append(Instruction(newOp, inouts: Array(newInputs) + newOutputs, flags: instr.flags)) } @@ -2147,18 +2298,21 @@ public class ProgramBuilder { var numberOfGeneratedInstructions = 0 // Calculate all input requirements of this CodeGenerator. - let inputRequirements = Set(generator.parts.reduce([]) { res, gen in - return res + gen.inputs.constraints - }) + let inputRequirements = Set( + generator.parts.reduce([]) { res, gen in + return res + gen.inputs.constraints + }) var fulfilledRequirements = inputRequirements.filter { requirement in - findVariable {requirement.fulfilled(by: self.type(of: $0))} != nil + findVariable { requirement.fulfilled(by: self.type(of: $0)) } != nil } // Add the current context to the seen Contexts as well. var seenContexts: [Context] = [context] - let contextsAndRequirements = generator.parts.map { ($0.providedContext, $0.inputs.constraints) } + let contextsAndRequirements = generator.parts.map { + ($0.providedContext, $0.inputs.constraints) + } // Check if the can be produced along this generator, otherwise we need to bail. for (contexts, requirements) in contextsAndRequirements { @@ -2171,7 +2325,14 @@ public class ProgramBuilder { // If we don't have the type available, check if we can produce it in the current context or a seen context. if !fulfilledRequirements.contains(where: requirement.fulfilled) { // Check if we have generators that can produce the type reachable from this context. - let reachableContexts: Context = seenContexts.reduce(Context.empty) { res, ctx in [res, fuzzer.contextGraph.getReachableContexts(from: ctx).reduce(Context.empty) { res, ctx in [res, ctx]}] + let reachableContexts: Context = seenContexts.reduce(Context.empty) { + res, ctx in + [ + res, + fuzzer.contextGraph.getReachableContexts(from: ctx).reduce( + Context.empty + ) { res, ctx in [res, ctx] }, + ] } // Right now this checks if the generator is a subset of the full reachable context (a single bitfield with all reachable contexts). @@ -2189,7 +2350,10 @@ public class ProgramBuilder { // We cannot run if this is false. if !canProduceThisType { // TODO(cffsmith): track some statistics on how often this happens. - buildLog?.reportFailure(reason: "Cannot produce type \(requirement) starting in original context \(context).") + buildLog?.reportFailure( + reason: + "Cannot produce type \(requirement) starting in original context \(context)." + ) return 0 } else { // Mark the type as available. @@ -2217,7 +2381,10 @@ public class ProgramBuilder { return [res, context] } - assert(subsetContext.isSubset(of: context), "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.head.name).") + assert( + subsetContext.isSubset(of: context), + "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.head.name)." + ) // While our local stack is not removed, we need to call into build and call the scheduled stubs. while scheduled.count > depth { @@ -2227,16 +2394,16 @@ public class ProgramBuilder { // Build into the block. buildRecursive(n: budgetPerYieldPoint) // Call the next scheduled stub. - let _ = callNext() + let _ = callNext() numberOfGeneratedInstructions += code.count - codeSizePre } if numberOfGeneratedInstructions > 0 { buildLog?.succeedAction( Set(visibleVariables) - .subtracting(Set(visibleVariablesBefore)) - .map(self.type) - ) + .subtracting(Set(visibleVariablesBefore)) + .map(self.type) + ) } else { buildLog?.reportFailure() } @@ -2255,12 +2422,12 @@ public class ProgramBuilder { // Check if we can produce it with findOrGenerateWasmVar let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) } - if (findVariable {requirement.fulfilled(by: self.type(of: $0))} == nil) { + if findVariable { requirement.fulfilled(by: self.type(of: $0)) } == nil { // Check for other CodeGenerators that can produce the given type in this context. let usableGenerators = fuzzer.codeGenerators.filter { - $0.requiredContext.isSubset(of: context) && - $0.produces.contains(where: requirement.fulfilled) + $0.requiredContext.isSubset(of: context) + && $0.produces.contains(where: requirement.fulfilled) } // Cannot build type here. @@ -2289,7 +2456,9 @@ public class ProgramBuilder { if context.contains(possibleContext) { // Walk through generated Graph and find a path. - let paths = fuzzer.contextGraph.getCodeGeneratorPaths(from: possibleContext, to: mainGenerator.requiredContext) ?? [] + let paths = + fuzzer.contextGraph.getCodeGeneratorPaths( + from: possibleContext, to: mainGenerator.requiredContext) ?? [] return pathArray + paths } @@ -2297,7 +2466,9 @@ public class ProgramBuilder { } if paths.isEmpty { - logger.warning("Found no paths in context \(context) for requested generator \(mainGenerator.name)") + logger.warning( + "Found no paths in context \(context) for requested generator \(mainGenerator.name)" + ) return nil } @@ -2350,8 +2521,10 @@ public class ProgramBuilder { return [res, context] } - assert(subsetContext.isSubset(of: context), "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.name).") - + assert( + subsetContext.isSubset(of: context), + "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.name)." + ) return generatedInstructions } else { @@ -2372,18 +2545,24 @@ public class ProgramBuilder { switch generator.inputs.mode { case .loose: // Find inputs that are probably compatible with the desired input types using randomVariable(forUseAs:) - inputs = generator.inputs.constraints.map {randomVariable(forUseAs: $0.type)} + inputs = generator.inputs.constraints.map { randomVariable(forUseAs: $0.type) } case .strict: // Find inputs of the required type using randomVariable(ofType:) for requirement in generator.inputs.constraints { - guard let input = (findVariable {requirement.fulfilled(by: self.type(of: $0))}) else { + guard let input = (findVariable { requirement.fulfilled(by: self.type(of: $0)) }) + else { // Cannot run this generator if generator.providedContext != [] { - fatalError("This generator is supposed to provide a context but cannot as we've failed to find the necessary inputs.") + fatalError( + "This generator is supposed to provide a context but cannot as we've failed to find the necessary inputs." + ) } // This early return also needs to report a failure. - buildLog?.reportFailure(reason: "Cannot find variable that satifies input constraints \(requirement.type).") + buildLog?.reportFailure( + reason: + "Cannot find variable that satifies input constraints \(requirement.type)." + ) return 0 } inputs.append(input) @@ -2396,9 +2575,9 @@ public class ProgramBuilder { contributors.insert(generator) buildLog?.succeedAction( Set(visibleVariables) - .subtracting(Set(visibleVariablesBefore)) - .map(self.type) - ) + .subtracting(Set(visibleVariablesBefore)) + .map(self.type) + ) } else { buildLog?.reportFailure(reason: "Generator itself failed to produce any instructions.") } @@ -2420,7 +2599,9 @@ public class ProgramBuilder { do { let program = Program(with: self.code) let pb = try program.asProtobuf().serializedData() - fuzzer.dispatchEvent(fuzzer.events.DiagnosticsEvent, data: (name: "WasmProgramBuildingEmissionFail", content: pb)) + fuzzer.dispatchEvent( + fuzzer.events.DiagnosticsEvent, + data: (name: "WasmProgramBuildingEmissionFail", content: pb)) } catch { logger.warning("Could not dump program to disk!") } @@ -2430,7 +2611,9 @@ public class ProgramBuilder { } @discardableResult - public func emit(_ op: Operation, withInputs inputs: [Variable] = [], types: [ILType]? = nil) -> Instruction { + public func emit(_ op: Operation, withInputs inputs: [Variable] = [], types: [ILType]? = nil) + -> Instruction + { var inouts = inputs for _ in 0.. ()) { + public func addMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit( + BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralMethod()) } - public func addComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit( + BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralComputedMethod()) } - public func addGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginObjectLiteralGetter(propertyName: name)) body(instr.innerOutput) b.emit(EndObjectLiteralGetter()) } - public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginObjectLiteralComputedGetter(), withInputs: [name]) body(instr.innerOutput) b.emit(EndObjectLiteralComputedGetter()) } - public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void) + { let instr = b.emit(BeginObjectLiteralSetter(propertyName: name)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralSetter()) } - public func addComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginObjectLiteralComputedSetter(), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralComputedSetter()) @@ -2608,7 +2803,7 @@ public class ProgramBuilder { } @discardableResult - public func buildObjectLiteral(_ body: (ObjectLiteral) -> ()) -> Variable { + public func buildObjectLiteral(_ body: (ObjectLiteral) -> Void) -> Variable { emit(BeginObjectLiteral()) body(currentObjectLiteral) return emit(EndObjectLiteral()).output @@ -2672,62 +2867,83 @@ public class ProgramBuilder { self.isDerivedClass = isDerived } - public func addConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addConstructor( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit(BeginClassConstructor(parameters: descriptor.parameters)) body(Array(instr.innerOutputs)) b.emit(EndClassConstructor()) } - public func addInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), + withInputs: inputs) } public func addInstanceElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddElement(index: index, hasValue: value != nil, isStatic: false), + withInputs: inputs) } public func addInstanceComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddComputedProperty(hasValue: value != nil, isStatic: false), + withInputs: inputs) } - public func addInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) + let instr = b.emit( + BeginClassMethod( + methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } - public func addInstanceComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addInstanceComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), withInputs: [name]) + let instr = b.emit( + BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } - public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: false)) body(instr.innerOutput) b.emit(EndClassGetter()) } - public func addInstanceComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addInstanceComputedGetter( + for name: Variable, _ body: (_ this: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedGetter(isStatic: false), withInputs: [name]) body(instr.innerOutput) b.emit(EndClassComputedGetter()) } - public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addInstanceSetter( + for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } - public func addInstanceComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addInstanceComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedSetter(isStatic: false), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassComputedSetter()) @@ -2735,58 +2951,77 @@ public class ProgramBuilder { public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), + withInputs: inputs) } public func addStaticElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddElement(index: index, hasValue: value != nil, isStatic: true), + withInputs: inputs) } public func addStaticComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs + ) } - public func addStaticInitializer(_ body: (Variable) -> ()) { + public func addStaticInitializer(_ body: (Variable) -> Void) { let instr = b.emit(BeginClassStaticInitializer()) body(instr.innerOutput) b.emit(EndClassStaticInitializer()) } - public func addStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addStaticMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) + let instr = b.emit( + BeginClassMethod( + methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } - public func addStaticComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addStaticComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), withInputs: [name]) + let instr = b.emit( + BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } - public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: true)) body(instr.innerOutput) b.emit(EndClassGetter()) } - public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> Void) + { let instr = b.emit(BeginClassComputedGetter(isStatic: true), withInputs: [name]) body(instr.innerOutput) b.emit(EndClassComputedGetter()) } - public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addStaticSetter( + for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } - public func addStaticComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addStaticComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedSetter(isStatic: true), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassComputedSetter()) @@ -2794,33 +3029,52 @@ public class ProgramBuilder { public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddPrivateProperty( + propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs + ) } - public func addPrivateInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addPrivateInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) + let instr = b.emit( + BeginClassPrivateMethod( + methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } public func addPrivateStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), + withInputs: inputs) } - public func addPrivateStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addPrivateStaticMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) + let instr = b.emit( + BeginClassPrivateMethod( + methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } } @discardableResult - public func buildClassDefinition(withSuperclass superclass: Variable? = nil, isExpression: Bool = false, _ body: (ClassDefinition) -> ()) -> Variable { + public func buildClassDefinition( + withSuperclass superclass: Variable? = nil, isExpression: Bool = false, + _ body: (ClassDefinition) -> Void + ) -> Variable { let inputs = superclass != nil ? [superclass!] : [] - let output = emit(BeginClassDefinition(hasSuperclass: superclass != nil, isExpression: isExpression), withInputs: inputs).output + let output = emit( + BeginClassDefinition(hasSuperclass: superclass != nil, isExpression: isExpression), + withInputs: inputs + ).output bodyWithRecursionGuard(output) { body(currentClassDefinition) } emit(EndClassDefinition()) return output @@ -2828,7 +3082,8 @@ public class ProgramBuilder { @discardableResult public func createArray(with initialValues: [Variable]) -> Variable { - return emit(CreateArray(numInitialValues: initialValues.count), withInputs: initialValues).output + return emit(CreateArray(numInitialValues: initialValues.count), withInputs: initialValues) + .output } @discardableResult @@ -2848,25 +3103,36 @@ public class ProgramBuilder { } @discardableResult - public func createTemplateString(from parts: [String], interpolating interpolatedValues: [Variable]) -> Variable { + public func createTemplateString( + from parts: [String], interpolating interpolatedValues: [Variable] + ) -> Variable { return emit(CreateTemplateString(parts: parts), withInputs: interpolatedValues).output } @discardableResult - public func getProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) -> Variable { - return emit(GetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]).output + public func getProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) + -> Variable + { + return emit(GetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]) + .output } - public func setProperty(_ name: String, of object: Variable, to value: Variable, guard isGuarded: Bool = false) { + public func setProperty( + _ name: String, of object: Variable, to value: Variable, guard isGuarded: Bool = false + ) { emit(SetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object, value]) } - public func updateProperty(_ name: String, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updateProperty( + _ name: String, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateProperty(propertyName: name, operator: op), withInputs: [object, value]) } @discardableResult - public func deleteProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) + -> Variable + { emit(DeleteProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]).output } @@ -2877,21 +3143,34 @@ public class ProgramBuilder { case getterSetter(Variable, Variable) } - public func configureProperty(_ name: String, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureProperty( + _ name: String, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .value), withInputs: [object, value]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .value), + withInputs: [object, value]) case .getter(let getter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .getter), withInputs: [object, getter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .getter), + withInputs: [object, getter]) case .setter(let setter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .setter), withInputs: [object, setter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .setter), + withInputs: [object, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .getterSetter), withInputs: [object, getter, setter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .getterSetter), + withInputs: [object, getter, setter]) } } @discardableResult - public func getElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) -> Variable { + public func getElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) + -> Variable + { return emit(GetElement(index: index, isGuarded: isGuarded), withInputs: [array]).output } @@ -2899,30 +3178,47 @@ public class ProgramBuilder { emit(SetElement(index: index), withInputs: [array, value]) } - public func updateElement(_ index: Int64, of array: Variable, with value: Variable, using op: BinaryOperator) { + public func updateElement( + _ index: Int64, of array: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateElement(index: index, operator: op), withInputs: [array, value]) } @discardableResult - public func deleteElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) + -> Variable + { emit(DeleteElement(index: index, isGuarded: isGuarded), withInputs: [array]).output } - public func configureElement(_ index: Int64, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureElement( + _ index: Int64, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureElement(index: index, flags: flags, type: .value), withInputs: [object, value]) + emit( + ConfigureElement(index: index, flags: flags, type: .value), + withInputs: [object, value]) case .getter(let getter): - emit(ConfigureElement(index: index, flags: flags, type: .getter), withInputs: [object, getter]) + emit( + ConfigureElement(index: index, flags: flags, type: .getter), + withInputs: [object, getter]) case .setter(let setter): - emit(ConfigureElement(index: index, flags: flags, type: .setter), withInputs: [object, setter]) + emit( + ConfigureElement(index: index, flags: flags, type: .setter), + withInputs: [object, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureElement(index: index, flags: flags, type: .getterSetter), withInputs: [object, getter, setter]) + emit( + ConfigureElement(index: index, flags: flags, type: .getterSetter), + withInputs: [object, getter, setter]) } } @discardableResult - public func getComputedProperty(_ name: Variable, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func getComputedProperty( + _ name: Variable, of object: Variable, guard isGuarded: Bool = false + ) -> Variable { return emit(GetComputedProperty(isGuarded: isGuarded), withInputs: [object, name]).output } @@ -2930,25 +3226,40 @@ public class ProgramBuilder { emit(SetComputedProperty(), withInputs: [object, name, value]) } - public func updateComputedProperty(_ name: Variable, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updateComputedProperty( + _ name: Variable, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateComputedProperty(operator: op), withInputs: [object, name, value]) } @discardableResult - public func deleteComputedProperty(_ name: Variable, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteComputedProperty( + _ name: Variable, of object: Variable, guard isGuarded: Bool = false + ) -> Variable { emit(DeleteComputedProperty(isGuarded: isGuarded), withInputs: [object, name]).output } - public func configureComputedProperty(_ name: Variable, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureComputedProperty( + _ name: Variable, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureComputedProperty(flags: flags, type: .value), withInputs: [object, name, value]) + emit( + ConfigureComputedProperty(flags: flags, type: .value), + withInputs: [object, name, value]) case .getter(let getter): - emit(ConfigureComputedProperty(flags: flags, type: .getter), withInputs: [object, name, getter]) + emit( + ConfigureComputedProperty(flags: flags, type: .getter), + withInputs: [object, name, getter]) case .setter(let setter): - emit(ConfigureComputedProperty(flags: flags, type: .setter), withInputs: [object, name, setter]) + emit( + ConfigureComputedProperty(flags: flags, type: .setter), + withInputs: [object, name, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureComputedProperty(flags: flags, type: .getterSetter), withInputs: [object, name, getter, setter]) + emit( + ConfigureComputedProperty(flags: flags, type: .getterSetter), + withInputs: [object, name, getter, setter]) } } @@ -2974,7 +3285,9 @@ public class ProgramBuilder { public func explore(_ v: Variable, id: String, withArgs arguments: [Variable]) { let rngSeed = UInt32(truncatingIfNeeded: randomInt()) - emit(Explore(id: id, numArguments: arguments.count, rngSeed: rngSeed), withInputs: [v] + arguments) + emit( + Explore(id: id, numArguments: arguments.count, rngSeed: rngSeed), + withInputs: [v] + arguments) } public func probe(_ v: Variable, id: String) { @@ -2982,8 +3295,14 @@ public class ProgramBuilder { } @discardableResult - public func fixup(id: String, action: String, originalOperation: String, arguments: [Variable], hasOutput: Bool) -> Variable? { - let instr = emit(Fixup(id: id, action: action, originalOperation: originalOperation, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) + public func fixup( + id: String, action: String, originalOperation: String, arguments: [Variable], + hasOutput: Bool + ) -> Variable? { + let instr = emit( + Fixup( + id: id, action: action, originalOperation: originalOperation, + numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) return hasOutput ? instr.output : nil } @@ -3005,8 +3324,11 @@ public class ProgramBuilder { return parameters.count } - public static func parameters(n: Int, hasRestParameter: Bool = false) -> SubroutineDescriptor { - return SubroutineDescriptor(withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) + public static func parameters(n: Int, hasRestParameter: Bool = false) + -> SubroutineDescriptor + { + return SubroutineDescriptor( + withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) } public static func parameters(_ params: Parameter...) -> SubroutineDescriptor { @@ -3014,35 +3336,48 @@ public class ProgramBuilder { } public static func parameters(_ parameterTypes: ParameterList) -> SubroutineDescriptor { - let parameters = Parameters(count: parameterTypes.count, hasRestParameter: parameterTypes.hasRestParameter) + let parameters = Parameters( + count: parameterTypes.count, hasRestParameter: parameterTypes.hasRestParameter) return SubroutineDescriptor(withParameters: parameters, ofTypes: parameterTypes) } - private init(withParameters parameters: Parameters, ofTypes parameterTypes: ParameterList? = nil) { + private init( + withParameters parameters: Parameters, ofTypes parameterTypes: ParameterList? = nil + ) { if let types = parameterTypes { assert(types.areValid()) assert(types.count == parameters.count) assert(types.hasRestParameter == parameters.hasRestParameter) self.parameterTypes = types } else { - self.parameterTypes = ParameterList(numParameters: parameters.count, hasRestParam: parameters.hasRestParameter) - assert(self.parameterTypes.allSatisfy({ $0 == .plain(.jsAnything) || $0 == .rest(.jsAnything) })) + self.parameterTypes = ParameterList( + numParameters: parameters.count, hasRestParam: parameters.hasRestParameter) + assert( + self.parameterTypes.allSatisfy({ + $0 == .plain(.jsAnything) || $0 == .rest(.jsAnything) + })) } self.parameters = parameters } } @discardableResult - public func buildPlainFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil,_ body: ([Variable]) -> ()) -> Variable { + public func buildPlainFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndPlainFunction()) return instr.output } @discardableResult - public func buildArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildArrowFunction( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3051,25 +3386,35 @@ public class ProgramBuilder { } @discardableResult - public func buildGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndGeneratorFunction()) return instr.output } @discardableResult - public func buildAsyncFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncFunction()) return instr.output } @discardableResult - public func buildAsyncArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncArrowFunction( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3078,16 +3423,23 @@ public class ProgramBuilder { } @discardableResult - public func buildAsyncGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginAsyncGeneratorFunction( + parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncGeneratorFunction()) return instr.output } @discardableResult - public func buildConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildConstructor( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginConstructor(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3132,36 +3484,73 @@ public class ProgramBuilder { } @discardableResult - public func callFunction(_ function: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallFunction(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [function] + arguments).output + public func callFunction( + _ function: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallFunction(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [function] + arguments + ).output } @discardableResult - public func callFunction(_ function: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func callFunction( + _ function: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], + guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return callFunction(function, withArgs: arguments) } - return emit(CallFunctionWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [function] + arguments).output + return emit( + CallFunctionWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [function] + arguments + ).output } @discardableResult - public func construct(_ constructor: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(Construct(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [constructor] + arguments).output + public func construct( + _ constructor: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false + ) -> Variable { + return emit( + Construct(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [constructor] + arguments + ).output } @discardableResult - public func construct(_ constructor: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func construct( + _ constructor: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], + guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return construct(constructor, withArgs: arguments) } - return emit(ConstructWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [constructor] + arguments).output + return emit( + ConstructWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [constructor] + arguments + ).output } @discardableResult - public func callMethod(_ name: String, on object: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallMethod(methodName: name, numArguments: arguments.count, isGuarded: isGuarded), withInputs: [object] + arguments).output + public func callMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable] = [], + guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallMethod(methodName: name, numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [object] + arguments + ).output } @discardableResult - public func callMethod(_ name: String, on object: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func callMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable], + spreading spreads: [Bool], guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return callMethod(name, on: object, withArgs: arguments) } - return emit(CallMethodWithSpread(methodName: name, numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [object] + arguments).output + return emit( + CallMethodWithSpread( + methodName: name, numArguments: arguments.count, spreads: spreads, + isGuarded: isGuarded), withInputs: [object] + arguments + ).output } @discardableResult @@ -3171,18 +3560,34 @@ public class ProgramBuilder { @discardableResult public func bindFunction(_ fct: Variable, boundArgs arguments: [Variable]) -> Variable { - return emit(BindFunction(numInputs: arguments.count + 1), withInputs: [fct] + arguments).output + return emit(BindFunction(numInputs: arguments.count + 1), withInputs: [fct] + arguments) + .output } @discardableResult - public func callComputedMethod(_ name: Variable, on object: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallComputedMethod(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [object, name] + arguments).output + public func callComputedMethod( + _ name: Variable, on object: Variable, withArgs arguments: [Variable] = [], + guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallComputedMethod(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [object, name] + arguments + ).output } @discardableResult - public func callComputedMethod(_ name: Variable, on object: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { - guard !spreads.isEmpty else { return callComputedMethod(name, on: object, withArgs: arguments) } - return emit(CallComputedMethodWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [object, name] + arguments).output + public func callComputedMethod( + _ name: Variable, on object: Variable, withArgs arguments: [Variable], + spreading spreads: [Bool], guard isGuarded: Bool = false + ) -> Variable { + guard !spreads.isEmpty else { + return callComputedMethod(name, on: object, withArgs: arguments) + } + return emit( + CallComputedMethodWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [object, name] + arguments + ).output } @discardableResult @@ -3214,35 +3619,59 @@ public class ProgramBuilder { } @discardableResult - public func destruct(_ input: Variable, selecting indices: [Int64], lastIsRest: Bool = false) -> [Variable] { - let outputs = emit(DestructArray(indices: indices, lastIsRest: lastIsRest), withInputs: [input]).outputs + public func destruct(_ input: Variable, selecting indices: [Int64], lastIsRest: Bool = false) + -> [Variable] + { + let outputs = emit( + DestructArray(indices: indices, lastIsRest: lastIsRest), withInputs: [input] + ).outputs return Array(outputs) } - public func destruct(_ input: Variable, selecting indices: [Int64], into outputs: [Variable], lastIsRest: Bool = false) { - emit(DestructArrayAndReassign(indices: indices, lastIsRest: lastIsRest), withInputs: [input] + outputs) + public func destruct( + _ input: Variable, selecting indices: [Int64], into outputs: [Variable], + lastIsRest: Bool = false + ) { + emit( + DestructArrayAndReassign(indices: indices, lastIsRest: lastIsRest), + withInputs: [input] + outputs) } @discardableResult - public func destruct(_ input: Variable, selecting properties: [String], hasRestElement: Bool = false) -> [Variable] { - let outputs = emit(DestructObject(properties: properties, hasRestElement: hasRestElement), withInputs: [input]).outputs + public func destruct( + _ input: Variable, selecting properties: [String], hasRestElement: Bool = false + ) -> [Variable] { + let outputs = emit( + DestructObject(properties: properties, hasRestElement: hasRestElement), + withInputs: [input] + ).outputs return Array(outputs) } - public func destruct(_ input: Variable, selecting properties: [String], into outputs: [Variable], hasRestElement: Bool = false) { - emit(DestructObjectAndReassign(properties: properties, hasRestElement: hasRestElement), withInputs: [input] + outputs) + public func destruct( + _ input: Variable, selecting properties: [String], into outputs: [Variable], + hasRestElement: Bool = false + ) { + emit( + DestructObjectAndReassign(properties: properties, hasRestElement: hasRestElement), + withInputs: [input] + outputs) } @discardableResult - public func compare(_ lhs: Variable, with rhs: Variable, using comparator: Comparator) -> Variable { + public func compare(_ lhs: Variable, with rhs: Variable, using comparator: Comparator) + -> Variable + { return emit(Compare(comparator), withInputs: [lhs, rhs]).output } @discardableResult - public func createNamedVariable(_ name: String, declarationMode: NamedVariableDeclarationMode, initialValue: Variable? = nil) -> Variable { + public func createNamedVariable( + _ name: String, declarationMode: NamedVariableDeclarationMode, initialValue: Variable? = nil + ) -> Variable { assert((declarationMode == .none) == (initialValue == nil)) let inputs = initialValue != nil ? [initialValue!] : [] - return emit(CreateNamedVariable(name, declarationMode: declarationMode), withInputs: inputs).output + return emit(CreateNamedVariable(name, declarationMode: declarationMode), withInputs: inputs) + .output } @discardableResult @@ -3251,12 +3680,15 @@ public class ProgramBuilder { } @discardableResult - public func createNamedDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable { + public func createNamedDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable + { return emit(CreateNamedDisposableVariable(name), withInputs: [initialValue]).output } @discardableResult - public func createNamedAsyncDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable { + public func createNamedAsyncDisposableVariable(_ name: String, _ initialValue: Variable) + -> Variable + { return emit(CreateNamedAsyncDisposableVariable(name), withInputs: [initialValue]).output } @@ -3270,8 +3702,12 @@ public class ProgramBuilder { } @discardableResult - public func eval(_ string: String, with arguments: [Variable] = [], hasOutput: Bool = false) -> Variable? { - let instr = emit(Eval(string, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) + public func eval(_ string: String, with arguments: [Variable] = [], hasOutput: Bool = false) + -> Variable? + { + let instr = emit( + Eval(string, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments + ) return hasOutput ? instr.output : nil } @@ -3291,7 +3727,9 @@ public class ProgramBuilder { @discardableResult public func callSuperMethod(_ name: String, withArgs arguments: [Variable] = []) -> Variable { - return emit(CallSuperMethod(methodName: name, numArguments: arguments.count), withInputs: arguments).output + return emit( + CallSuperMethod(methodName: name, numArguments: arguments.count), withInputs: arguments + ).output } @discardableResult @@ -3303,13 +3741,20 @@ public class ProgramBuilder { emit(SetPrivateProperty(propertyName: name), withInputs: [object, value]) } - public func updatePrivateProperty(_ name: String, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updatePrivateProperty( + _ name: String, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdatePrivateProperty(propertyName: name, operator: op), withInputs: [object, value]) } @discardableResult - public func callPrivateMethod(_ name: String, on object: Variable, withArgs arguments: [Variable] = []) -> Variable { - return emit(CallPrivateMethod(methodName: name, numArguments: arguments.count), withInputs: [object] + arguments).output + public func callPrivateMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable] = [] + ) -> Variable { + return emit( + CallPrivateMethod(methodName: name, numArguments: arguments.count), + withInputs: [object] + arguments + ).output } @discardableResult @@ -3330,7 +3775,8 @@ public class ProgramBuilder { emit(SetComputedSuperProperty(), withInputs: [property, value]) } - public func updateSuperProperty(_ name: String, with value: Variable, using op: BinaryOperator) { + public func updateSuperProperty(_ name: String, with value: Variable, using op: BinaryOperator) + { emit(UpdateSuperProperty(propertyName: name, operator: op), withInputs: [value]) } @@ -3357,20 +3803,20 @@ public class ProgramBuilder { self.b = b } - public func addDefaultCase(fallsThrough: Bool = false, body: @escaping () -> ()) { + public func addDefaultCase(fallsThrough: Bool = false, body: @escaping () -> Void) { b.emit(BeginSwitchDefaultCase(), withInputs: []) body() b.emit(EndSwitchCase(fallsThrough: fallsThrough)) } - public func addCase(_ v: Variable, fallsThrough: Bool = false, body: @escaping () -> ()) { + public func addCase(_ v: Variable, fallsThrough: Bool = false, body: @escaping () -> Void) { b.emit(BeginSwitchCase(), withInputs: [v]) body() b.emit(EndSwitchCase(fallsThrough: fallsThrough)) } } - public func buildSwitch(on switchVar: Variable, body: (SwitchBlock) -> ()) { + public func buildSwitch(on switchVar: Variable, body: (SwitchBlock) -> Void) { emit(BeginSwitch(), withInputs: [switchVar]) body(currentSwitchBlock) emit(EndSwitch()) @@ -3397,12 +3843,17 @@ public class ProgramBuilder { } // Build a simple for loop that declares one loop variable. - public func buildForLoop(i initializer: () -> Variable, _ cond: (Variable) -> Variable, _ afterthought: (Variable) -> (), _ body: (Variable) -> ()) { + public func buildForLoop( + i initializer: () -> Variable, _ cond: (Variable) -> Variable, + _ afterthought: (Variable) -> Void, _ body: (Variable) -> Void + ) { emit(BeginForLoopInitializer()) let initialValue = initializer() - var loopVar = emit(BeginForLoopCondition(numLoopVariables: 1), withInputs: [initialValue]).innerOutput + var loopVar = emit(BeginForLoopCondition(numLoopVariables: 1), withInputs: [initialValue]) + .innerOutput let cond = cond(loopVar) - loopVar = emit(BeginForLoopAfterthought(numLoopVariables: 1), withInputs: [cond]).innerOutput + loopVar = + emit(BeginForLoopAfterthought(numLoopVariables: 1), withInputs: [cond]).innerOutput afterthought(loopVar) loopVar = emit(BeginForLoopBody(numLoopVariables: 1)).innerOutput body(loopVar) @@ -3410,7 +3861,10 @@ public class ProgramBuilder { } // Build arbitrarily complex for loops without any loop variables. - public func buildForLoop(_ initializer: (() -> ())? = nil, _ cond: (() -> Variable)? = nil, _ afterthought: (() -> ())? = nil, _ body: () -> ()) { + public func buildForLoop( + _ initializer: (() -> Void)? = nil, _ cond: (() -> Variable)? = nil, + _ afterthought: (() -> Void)? = nil, _ body: () -> Void + ) { emit(BeginForLoopInitializer()) initializer?() emit(BeginForLoopCondition(numLoopVariables: 0)) @@ -3423,43 +3877,56 @@ public class ProgramBuilder { } // Build arbitrarily complex for loops with one or more loop variables. - public func buildForLoop(_ initializer: () -> [Variable], _ cond: (([Variable]) -> Variable)? = nil, _ afterthought: (([Variable]) -> ())? = nil, _ body: ([Variable]) -> ()) { + public func buildForLoop( + _ initializer: () -> [Variable], _ cond: (([Variable]) -> Variable)? = nil, + _ afterthought: (([Variable]) -> Void)? = nil, _ body: ([Variable]) -> Void + ) { emit(BeginForLoopInitializer()) let initialValues = initializer() - var loopVars = emit(BeginForLoopCondition(numLoopVariables: initialValues.count), withInputs: initialValues).innerOutputs + var loopVars = emit( + BeginForLoopCondition(numLoopVariables: initialValues.count), withInputs: initialValues + ).innerOutputs let cond = cond?(Array(loopVars)) ?? loadBool(true) - loopVars = emit(BeginForLoopAfterthought(numLoopVariables: initialValues.count), withInputs: [cond]).innerOutputs + loopVars = + emit( + BeginForLoopAfterthought(numLoopVariables: initialValues.count), withInputs: [cond] + ).innerOutputs afterthought?(Array(loopVars)) loopVars = emit(BeginForLoopBody(numLoopVariables: initialValues.count)).innerOutputs body(Array(loopVars)) emit(EndForLoop()) } - public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> ()) { + public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> Void) { let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForInLoop()) } - public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) { + public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> Void) { let i = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForOfLoop()) } - public func buildForOfLoop(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) { - let instr = emit(BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), withInputs: [obj]) + public func buildForOfLoop( + _ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, + _ body: ([Variable]) -> Void + ) { + let instr = emit( + BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), + withInputs: [obj]) body(Array(instr.innerOutputs)) emit(EndForOfLoop()) } - public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> ()) { + public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> Void) { let i = emit(BeginRepeatLoop(iterations: numIterations)).innerOutput body(i) emit(EndRepeatLoop()) } - public func buildRepeatLoop(n numIterations: Int, _ body: () -> ()) { + public func buildRepeatLoop(n numIterations: Int, _ body: () -> Void) { emit(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) body() emit(EndRepeatLoop()) @@ -3473,8 +3940,13 @@ public class ProgramBuilder { emit(LoopContinue(), withInputs: []) } - public func buildTryCatchFinally(tryBody: () -> (), catchBody: ((Variable) -> ())? = nil, finallyBody: (() -> ())? = nil) { - assert(catchBody != nil || finallyBody != nil, "Must have either a Catch or a Finally block (or both)") + public func buildTryCatchFinally( + tryBody: () -> Void, catchBody: ((Variable) -> Void)? = nil, + finallyBody: (() -> Void)? = nil + ) { + assert( + catchBody != nil || finallyBody != nil, + "Must have either a Catch or a Finally block (or both)") emit(BeginTry()) tryBody() if let catchBody = catchBody { @@ -3492,7 +3964,7 @@ public class ProgramBuilder { emit(ThrowException(), withInputs: [value]) } - public func buildCodeString(_ body: () -> ()) -> Variable { + public func buildCodeString(_ body: () -> Void) -> Variable { let instr = emit(BeginCodeString()) body() emit(EndCodeString()) @@ -3509,7 +3981,6 @@ public class ProgramBuilder { emit(Print(), withInputs: [value]) } - @discardableResult public func createWasmGlobal(value: WasmGlobal, isMutable: Bool) -> Variable { let variable = emit(CreateWasmGlobal(value: value, isMutable: isMutable)).output @@ -3517,13 +3988,20 @@ public class ProgramBuilder { } @discardableResult - public func createWasmMemory(minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false) -> Variable { + public func createWasmMemory( + minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false + ) -> Variable { assert(!isShared || maxPages != nil, "Shared memories must have a maximum size") - return emit(CreateWasmMemory(limits: Limits(min: minPages, max: maxPages), isShared: isShared, isMemory64: isMemory64)).output + return emit( + CreateWasmMemory( + limits: Limits(min: minPages, max: maxPages), isShared: isShared, + isMemory64: isMemory64) + ).output } public func createWasmTable(elementType: ILType, limits: Limits, isTable64: Bool) -> Variable { - return emit(CreateWasmTable(elementType: elementType, limits: limits, isTable64: isTable64)).output + return emit(CreateWasmTable(elementType: elementType, limits: limits, isTable64: isTable64)) + .output } @discardableResult @@ -3573,7 +4051,7 @@ public class ProgramBuilder { @discardableResult public func memoryArgument(_ value: Int64, _ memoryTypeInfo: WasmMemoryType) -> Variable { - if (memoryTypeInfo.isMemory64) { + if memoryTypeInfo.isMemory64 { return self.consti64(value) } else { return self.consti32(Int32(value)) @@ -3591,43 +4069,67 @@ public class ProgramBuilder { } @discardableResult - public func wasmi64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind) -> Variable { - return b.emit(Wasmi64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmi64, .wasmi64]).output + public func wasmi64BinOp( + _ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind + ) -> Variable { + return b.emit( + Wasmi64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmi64, .wasmi64] + ).output } @discardableResult - public func wasmi32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind) -> Variable { - return b.emit(Wasmi32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmi32, .wasmi32]).output + public func wasmi32BinOp( + _ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind + ) -> Variable { + return b.emit( + Wasmi32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmi32, .wasmi32] + ).output } @discardableResult - public func wasmf32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) -> Variable { - return b.emit(Wasmf32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmf32, .wasmf32]).output + public func wasmf32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) + -> Variable + { + return b.emit( + Wasmf32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmf32, .wasmf32] + ).output } @discardableResult - public func wasmf64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) -> Variable { - return b.emit(Wasmf64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmf64, .wasmf64]).output + public func wasmf64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) + -> Variable + { + return b.emit( + Wasmf64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmf64, .wasmf64] + ).output } @discardableResult public func wasmi32UnOp(_ input: Variable, unOpKind: WasmIntegerUnaryOpKind) -> Variable { - return b.emit(Wasmi32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi32]).output + return b.emit(Wasmi32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi32]) + .output } @discardableResult public func wasmi64UnOp(_ input: Variable, unOpKind: WasmIntegerUnaryOpKind) -> Variable { - return b.emit(Wasmi64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi64]).output + return b.emit(Wasmi64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi64]) + .output } @discardableResult public func wasmf32UnOp(_ input: Variable, unOpKind: WasmFloatUnaryOpKind) -> Variable { - return b.emit(Wasmf32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf32]).output + return b.emit(Wasmf32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf32]) + .output } @discardableResult public func wasmf64UnOp(_ input: Variable, unOpKind: WasmFloatUnaryOpKind) -> Variable { - return b.emit(Wasmf64UnOp(unOpKind: unOpKind), withInputs: [input],types: [.wasmf64]).output + return b.emit(Wasmf64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf64]) + .output } @discardableResult @@ -3641,23 +4143,43 @@ public class ProgramBuilder { } @discardableResult - public func wasmi32CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind) -> Variable { - return b.emit(Wasmi32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmi32, .wasmi32]).output + public func wasmi32CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind + ) -> Variable { + return b.emit( + Wasmi32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmi32, .wasmi32] + ).output } @discardableResult - public func wasmi64CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind) -> Variable { - return b.emit(Wasmi64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmi64, .wasmi64]).output + public func wasmi64CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind + ) -> Variable { + return b.emit( + Wasmi64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmi64, .wasmi64] + ).output } @discardableResult - public func wasmf64CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind) -> Variable { - return b.emit(Wasmf64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmf64, .wasmf64]).output + public func wasmf64CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind + ) -> Variable { + return b.emit( + Wasmf64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmf64, .wasmf64] + ).output } @discardableResult - public func wasmf32CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind) -> Variable { - return b.emit(Wasmf32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmf32, .wasmf32]).output + public func wasmf32CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind + ) -> Variable { + return b.emit( + Wasmf32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmf32, .wasmf32] + ).output } @discardableResult @@ -3667,37 +4189,51 @@ public class ProgramBuilder { @discardableResult public func truncatef32Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncatef32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncatef64Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncatef64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func extendi32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmExtendi32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmExtendi32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func truncatef32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncatef32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncatef64Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncatef64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func converti32Tof32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti32Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmConverti32Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func converti64Tof32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti64Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi64]).output + return b.emit( + WasmConverti64Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi64] + ).output } @discardableResult @@ -3707,12 +4243,16 @@ public class ProgramBuilder { @discardableResult public func converti32Tof64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti32Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmConverti32Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func converti64Tof64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti64Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi64]).output + return b.emit( + WasmConverti64Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi64] + ).output } @discardableResult @@ -3767,102 +4307,157 @@ public class ProgramBuilder { @discardableResult public func truncateSatf32Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncateSatf32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncateSatf64Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncateSatf64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func truncateSatf32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncateSatf32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncateSatf64Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncateSatf64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func wasmLoadGlobal(globalVariable: Variable) -> Variable { let type = b.type(of: globalVariable).wasmGlobalType!.valueType - return b.emit(WasmLoadGlobal(globalType: type), withInputs:[globalVariable], types: [ILType.object(ofGroup: "WasmGlobal")]).output + return b.emit( + WasmLoadGlobal(globalType: type), withInputs: [globalVariable], + types: [ILType.object(ofGroup: "WasmGlobal")] + ).output } public func wasmStoreGlobal(globalVariable: Variable, to value: Variable) { let type = b.type(of: globalVariable).wasmGlobalType!.valueType - let inputTypes = [ILType.object(ofGroup: "WasmGlobal", withWasmType: WasmGlobalType(valueType: type, isMutable: true)), type] - b.emit(WasmStoreGlobal(globalType: type), withInputs: [globalVariable, value], types: inputTypes) + let inputTypes = [ + ILType.object( + ofGroup: "WasmGlobal", + withWasmType: WasmGlobalType(valueType: type, isMutable: true)), type, + ] + b.emit( + WasmStoreGlobal(globalType: type), withInputs: [globalVariable, value], + types: inputTypes) } @discardableResult public func wasmTableGet(tableRef: Variable, idx: Variable) -> Variable { let tableType = b.type(of: tableRef) let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType]).output + return b.emit( + WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType] + ).output } public func wasmTableSet(tableRef: Variable, idx: Variable, to value: Variable) { let tableType = b.type(of: tableRef) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableSet(), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) + b.emit( + WasmTableSet(), withInputs: [tableRef, idx, value], + types: [tableType, offsetType, elementType]) } @discardableResult public func wasmTableSize(table: Variable) -> Variable { - return b.emit(WasmTableSize(), withInputs: [table], - types: [.object(ofGroup: "WasmTable")]).output + return b.emit( + WasmTableSize(), withInputs: [table], + types: [.object(ofGroup: "WasmTable")] + ).output } @discardableResult - public func wasmTableGrow(table: Variable, with initialValue: Variable, by delta: Variable) -> Variable { + public func wasmTableGrow(table: Variable, with initialValue: Variable, by delta: Variable) + -> Variable + { let tableType = b.type(of: table) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGrow(), withInputs: [table, initialValue, delta], - types: [.object(ofGroup: "WasmTable"), elementType, offsetType]).output + return b.emit( + WasmTableGrow(), withInputs: [table, initialValue, delta], + types: [.object(ofGroup: "WasmTable"), elementType, offsetType] + ).output } @discardableResult - public func wasmCallIndirect(signature: WasmSignature, table: Variable, functionArgs: [Variable], tableIndex: Variable) -> [Variable] { + public func wasmCallIndirect( + signature: WasmSignature, table: Variable, functionArgs: [Variable], + tableIndex: Variable + ) -> [Variable] { let isTable64 = b.type(of: table).wasmTableType!.isTable64 - return Array(b.emit(WasmCallIndirect(signature: signature), - withInputs: [table] + functionArgs + [tableIndex], - types: [.wasmTable] + signature.parameterTypes + [isTable64 ? .wasmi64 : .wasmi32] - ).outputs) + return Array( + b.emit( + WasmCallIndirect(signature: signature), + withInputs: [table] + functionArgs + [tableIndex], + types: [.wasmTable] + signature.parameterTypes + [ + isTable64 ? .wasmi64 : .wasmi32 + ] + ).outputs) } @discardableResult - public func wasmCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) -> [Variable] { - return Array(b.emit(WasmCallDirect(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), - withInputs: [function] + functionArgs, - types: [.wasmFunctionDef(signature)] + signature.parameterTypes - ).outputs) - } - - public func wasmReturnCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) { + public func wasmCallDirect( + signature: WasmSignature, function: Variable, functionArgs: [Variable] + ) -> [Variable] { + return Array( + b.emit( + WasmCallDirect( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), + withInputs: [function] + functionArgs, + types: [.wasmFunctionDef(signature)] + signature.parameterTypes + ).outputs) + } + + public func wasmReturnCallDirect( + signature: WasmSignature, function: Variable, functionArgs: [Variable] + ) { assert(self.signature.outputTypes == signature.outputTypes) - b.emit(WasmReturnCallDirect(parameterCount: signature.parameterTypes.count), + b.emit( + WasmReturnCallDirect(parameterCount: signature.parameterTypes.count), withInputs: [function] + functionArgs, types: [.wasmFunctionDef(signature)] + signature.parameterTypes) } - public func wasmReturnCallIndirect(signature: WasmSignature, table: Variable, functionArgs: [Variable], tableIndex: Variable) { + public func wasmReturnCallIndirect( + signature: WasmSignature, table: Variable, functionArgs: [Variable], + tableIndex: Variable + ) { let isTable64 = b.type(of: table).wasmTableType!.isTable64 assert(self.signature.outputTypes == signature.outputTypes) - b.emit(WasmReturnCallIndirect(signature: signature), + b.emit( + WasmReturnCallIndirect(signature: signature), withInputs: [table] + functionArgs + [tableIndex], types: [.wasmTable] + signature.parameterTypes + [isTable64 ? .wasmi64 : .wasmi32]) } @discardableResult - public func wasmJsCall(function: Variable, withArgs args: [Variable], withWasmSignature signature: WasmSignature) -> Variable? { + public func wasmJsCall( + function: Variable, withArgs args: [Variable], + withWasmSignature signature: WasmSignature + ) -> Variable? { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmJsCall(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), withInputs: [signatureDef, function] + args, - types: [.wasmTypeDef(), .function() | .object(ofGroup: "WasmSuspendingObject")] + signature.parameterTypes) + let instr = b.emit( + WasmJsCall( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), + withInputs: [signatureDef, function] + args, + types: [.wasmTypeDef(), .function() | .object(ofGroup: "WasmSuspendingObject")] + + signature.parameterTypes) if signature.outputTypes.isEmpty { assert(!instr.hasOutputs) return nil @@ -3873,78 +4468,132 @@ public class ProgramBuilder { } @discardableResult - public func wasmMemoryLoad(memory: Variable, dynamicOffset: Variable, loadType: WasmMemoryLoadType, staticOffset: Int64) -> Variable { + public func wasmMemoryLoad( + memory: Variable, dynamicOffset: Variable, loadType: WasmMemoryLoadType, + staticOffset: Int64 + ) -> Variable { let addrType = b.type(of: memory).wasmMemoryType!.addrType - return b.emit(WasmMemoryLoad(loadType: loadType, staticOffset: staticOffset), withInputs: [memory, dynamicOffset], types: [.object(ofGroup: "WasmMemory"), addrType]).output + return b.emit( + WasmMemoryLoad(loadType: loadType, staticOffset: staticOffset), + withInputs: [memory, dynamicOffset], + types: [.object(ofGroup: "WasmMemory"), addrType] + ).output } - public func wasmMemoryStore(memory: Variable, dynamicOffset: Variable, value: Variable, storeType: WasmMemoryStoreType, staticOffset: Int64) { + public func wasmMemoryStore( + memory: Variable, dynamicOffset: Variable, value: Variable, + storeType: WasmMemoryStoreType, staticOffset: Int64 + ) { assert(b.type(of: value) == storeType.numberType()) let addrType = b.type(of: memory).wasmMemoryType!.addrType - let inputTypes = [ILType.object(ofGroup: "WasmMemory"), addrType, storeType.numberType()] - b.emit(WasmMemoryStore(storeType: storeType, staticOffset: staticOffset), withInputs: [memory, dynamicOffset, value], types: inputTypes) + let inputTypes = [ + ILType.object(ofGroup: "WasmMemory"), addrType, storeType.numberType(), + ] + b.emit( + WasmMemoryStore(storeType: storeType, staticOffset: staticOffset), + withInputs: [memory, dynamicOffset, value], types: inputTypes) } @discardableResult - func wasmAtomicLoad(memory: Variable, address: Variable, loadType: WasmAtomicLoadType, offset: Int64) -> Variable { + func wasmAtomicLoad( + memory: Variable, address: Variable, loadType: WasmAtomicLoadType, offset: Int64 + ) -> Variable { let op = WasmAtomicLoad(loadType: loadType, offset: offset) return b.emit(op, withInputs: [memory, address]).output } - func wasmAtomicStore(memory: Variable, address: Variable, value: Variable, storeType: WasmAtomicStoreType, offset: Int64) { + func wasmAtomicStore( + memory: Variable, address: Variable, value: Variable, storeType: WasmAtomicStoreType, + offset: Int64 + ) { let op = WasmAtomicStore(storeType: storeType, offset: offset) b.emit(op, withInputs: [memory, address, value]) } @discardableResult - func wasmAtomicRMW(memory: Variable, lhs: Variable, rhs: Variable, op: WasmAtomicRMWType, offset: Int64) -> Variable { + func wasmAtomicRMW( + memory: Variable, lhs: Variable, rhs: Variable, op: WasmAtomicRMWType, offset: Int64 + ) -> Variable { let op = WasmAtomicRMW(op: op, offset: offset) let anyInt: ILType = .wasmi32 | .wasmi64 let valueType = op.op.type() - return b.emit(op, withInputs: [memory, lhs, rhs], types: [.object(ofGroup: "WasmMemory"), anyInt, valueType]).output + return b.emit( + op, withInputs: [memory, lhs, rhs], + types: [.object(ofGroup: "WasmMemory"), anyInt, valueType] + ).output } @discardableResult - func wasmAtomicCmpxchg(memory: Variable, address: Variable, expected: Variable, replacement: Variable, op: WasmAtomicCmpxchgType, offset: Int64) -> Variable { + func wasmAtomicCmpxchg( + memory: Variable, address: Variable, expected: Variable, replacement: Variable, + op: WasmAtomicCmpxchgType, offset: Int64 + ) -> Variable { let op = WasmAtomicCmpxchg(op: op, offset: offset) let anyInt: ILType = .wasmi32 | .wasmi64 let valueType = op.op.type() - return b.emit(op, withInputs: [memory, address, expected, replacement], types: [.object(ofGroup: "WasmMemory"), anyInt, valueType, valueType]).output + return b.emit( + op, withInputs: [memory, address, expected, replacement], + types: [.object(ofGroup: "WasmMemory"), anyInt, valueType, valueType] + ).output } @discardableResult public func wasmMemorySize(memory: Variable) -> Variable { - return b.emit(WasmMemorySize(), withInputs: [memory], - types: [.object(ofGroup: "WasmMemory")]).output + return b.emit( + WasmMemorySize(), withInputs: [memory], + types: [.object(ofGroup: "WasmMemory")] + ).output } @discardableResult public func wasmMemoryGrow(memory: Variable, growByPages: Variable) -> Variable { let addrType = b.type(of: memory).wasmMemoryType!.addrType - return b.emit(WasmMemoryGrow(), withInputs: [memory, growByPages], - types: [.object(ofGroup: "WasmMemory"), addrType]).output + return b.emit( + WasmMemoryGrow(), withInputs: [memory, growByPages], + types: [.object(ofGroup: "WasmMemory"), addrType] + ).output } - public func wasmMemoryCopy(dstMemory: Variable, srcMemory: Variable, dstOffset: Variable, srcOffset: Variable, size: Variable) { + public func wasmMemoryCopy( + dstMemory: Variable, srcMemory: Variable, dstOffset: Variable, srcOffset: Variable, + size: Variable + ) { let dstMemoryType = b.type(of: dstMemory).wasmMemoryType! let srcMemoryType = b.type(of: srcMemory).wasmMemoryType! assert(dstMemoryType.isMemory64 == srcMemoryType.isMemory64) let addrType = dstMemoryType.addrType - b.emit(WasmMemoryCopy(), withInputs: [dstMemory, srcMemory, dstOffset, srcOffset, size], - types: [.object(ofGroup: "WasmMemory"), .object(ofGroup: "WasmMemory"), addrType, addrType, addrType]) + b.emit( + WasmMemoryCopy(), withInputs: [dstMemory, srcMemory, dstOffset, srcOffset, size], + types: [ + .object(ofGroup: "WasmMemory"), .object(ofGroup: "WasmMemory"), addrType, + addrType, addrType, + ]) } - public func wasmMemoryFill(memory: Variable, offset: Variable, byteToSet: Variable, nrOfBytesToUpdate: Variable) { + public func wasmMemoryFill( + memory: Variable, offset: Variable, byteToSet: Variable, nrOfBytesToUpdate: Variable + ) { let addrType = b.type(of: memory).wasmMemoryType!.addrType - b.emit(WasmMemoryFill(), withInputs: [memory, offset, byteToSet, nrOfBytesToUpdate], + b.emit( + WasmMemoryFill(), withInputs: [memory, offset, byteToSet, nrOfBytesToUpdate], types: [.object(ofGroup: "WasmMemory"), addrType, .wasmi32, addrType]) } - public func wasmMemoryInit(dataSegment: Variable, memory: Variable, memoryOffset: Variable, dataSegmentOffset: Variable, nrOfBytesToUpdate: Variable) { + public func wasmMemoryInit( + dataSegment: Variable, memory: Variable, memoryOffset: Variable, + dataSegmentOffset: Variable, nrOfBytesToUpdate: Variable + ) { let addrType = b.type(of: memory).wasmMemoryType!.addrType - b.emit(WasmMemoryInit(), withInputs: [dataSegment, memory, memoryOffset, dataSegmentOffset, nrOfBytesToUpdate], - types: [.wasmDataSegment(), .object(ofGroup: "WasmMemory"), addrType, .wasmi32, .wasmi32]) + b.emit( + WasmMemoryInit(), + withInputs: [ + dataSegment, memory, memoryOffset, dataSegmentOffset, nrOfBytesToUpdate, + ], + types: [ + .wasmDataSegment(), .object(ofGroup: "WasmMemory"), addrType, .wasmi32, + .wasmi32, + ]) } public func wasmDropDataSegment(dataSegment: Variable) { @@ -3952,29 +4601,49 @@ public class ProgramBuilder { } public func wasmDropElementSegment(elementSegment: Variable) { - b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) + b.emit( + WasmDropElementSegment(), withInputs: [elementSegment], + types: [.wasmElementSegment()]) } // TODO(pawkra): support shared tables and element segments. - public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { + public func wasmTableInit( + elementSegment: Variable, table: Variable, tableOffset: Variable, + elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable + ) { let elementSegmentType = ILType.wasmFuncRef() let tableElemType = b.type(of: table).wasmTableType!.elementType assert(elementSegmentType.Is(tableElemType)) - let addrType = b.type(of: table).wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableInit(), withInputs: [elementSegment, table, tableOffset, elementSegmentOffset, nrOfElementsToUpdate], - types: [.wasmElementSegment(), .object(ofGroup: "WasmTable"), addrType, .wasmi32, .wasmi32]) - } - - public func wasmTableCopy(dstTable: Variable, srcTable: Variable, dstOffset: Variable, srcOffset: Variable, count: Variable) { + let addrType = + b.type(of: table).wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 + b.emit( + WasmTableInit(), + withInputs: [ + elementSegment, table, tableOffset, elementSegmentOffset, nrOfElementsToUpdate, + ], + types: [ + .wasmElementSegment(), .object(ofGroup: "WasmTable"), addrType, .wasmi32, + .wasmi32, + ]) + } + + public func wasmTableCopy( + dstTable: Variable, srcTable: Variable, dstOffset: Variable, srcOffset: Variable, + count: Variable + ) { let dstTableType = b.type(of: dstTable).wasmTableType! let srcTableType = b.type(of: srcTable).wasmTableType! assert(dstTableType.isTable64 == srcTableType.isTable64) assert(srcTableType.elementType.Is(dstTableType.elementType)) let addrType = dstTableType.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableCopy(), withInputs: [dstTable, srcTable, dstOffset, srcOffset, count], - types: [.object(ofGroup: "WasmTable"), .object(ofGroup: "WasmTable"), addrType, addrType, addrType]) + b.emit( + WasmTableCopy(), withInputs: [dstTable, srcTable, dstOffset, srcOffset, count], + types: [ + .object(ofGroup: "WasmTable"), .object(ofGroup: "WasmTable"), addrType, + addrType, addrType, + ]) } public func wasmReassign(variable: Variable, to: Variable) { @@ -3983,7 +4652,9 @@ public class ProgramBuilder { } // The first innerOutput of this block is a label variable, which is just there to explicitly mark control-flow and allow branches. - public func wasmBuildBlock(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> ()) { + public func wasmBuildBlock( + with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void + ) { assert(signature.outputTypes.count == 0) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let instr = b.emit( @@ -3995,36 +4666,46 @@ public class ProgramBuilder { } @discardableResult - public func wasmBuildBlockWithResults(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildBlockWithResults( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let instr = b.emit( WasmBeginBlock(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit( - WasmEndBlock(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + results, - types: [.wasmTypeDef()] + signature.outputTypes - ).outputs) + return Array( + b.emit( + WasmEndBlock(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + results, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } private func checkArgumentsMatchLabelType(label: ILType, args: [Variable]) { let parameterTypes = label.wasmLabelType!.parameters - let errorMsg = "label type \(label) doesn't match argument types \(args.map({b.type(of: $0)}))" + let errorMsg = + "label type \(label) doesn't match argument types \(args.map({b.type(of: $0)}))" assert(parameterTypes.count == args.count, errorMsg) // Each argument type must be a subtype of the corresponding label's parameter type. - assert(zip(parameterTypes, args).allSatisfy {b.type(of: $0.1).Is($0.0)}, errorMsg) + assert(zip(parameterTypes, args).allSatisfy { b.type(of: $0.1).Is($0.0) }, errorMsg) } // This can branch to label variables only, has a variable input for dataflow purposes. public func wasmBranch(to label: Variable, args: [Variable] = []) { let labelType = b.type(of: label) checkArgumentsMatchLabelType(label: labelType, args: args) - b.emit(WasmBranch(parameterCount: labelType.wasmLabelType!.parameters.count), withInputs: [label] + args) + b.emit( + WasmBranch(parameterCount: labelType.wasmLabelType!.parameters.count), + withInputs: [label] + args) } - public func wasmBranchIf(_ condition: Variable, to label: Variable, args: [Variable] = [], hint: WasmBranchHint = .None) { + public func wasmBranchIf( + _ condition: Variable, to label: Variable, args: [Variable] = [], + hint: WasmBranchHint = .None + ) { let labelType = b.type(of: label) checkArgumentsMatchLabelType(label: labelType, args: args) assert(b.type(of: condition).Is(.wasmi32)) @@ -4035,19 +4716,29 @@ public class ProgramBuilder { public func wasmBranchTable(on: Variable, labels: [Variable], args: [Variable]) { labels.forEach { checkArgumentsMatchLabelType(label: b.type(of: $0), args: args) } - b.emit(WasmBranchTable(parameterCount: args.count, valueCount: labels.count - 1), + b.emit( + WasmBranchTable(parameterCount: args.count, valueCount: labels.count - 1), withInputs: labels + args + [on]) } - public func wasmBuildIfElse(_ condition: Variable, signature: WasmSignature = [] => [], args: [Variable] = [], hint: WasmBranchHint = .None, inverted: Bool = false, ifBody: (Variable, [Variable]) -> Void, elseBody: ((Variable, [Variable]) -> Void)? = nil) { + public func wasmBuildIfElse( + _ condition: Variable, signature: WasmSignature = [] => [], args: [Variable] = [], + hint: WasmBranchHint = .None, inverted: Bool = false, + ifBody: (Variable, [Variable]) -> Void, + elseBody: ((Variable, [Variable]) -> Void)? = nil + ) { assert(signature.outputTypes.count == 0) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let beginBlock = b.emit(WasmBeginIf(parameterCount: signature.parameterTypes.count, inverted: inverted), + let beginBlock = b.emit( + WasmBeginIf(parameterCount: signature.parameterTypes.count, inverted: inverted), withInputs: [signatureDef] + args + [condition], types: [.wasmTypeDef()] + signature.parameterTypes + [.wasmi32]) ifBody(beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) if let elseBody { - let elseBlock = b.emit(WasmBeginElse(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), + let elseBlock = b.emit( + WasmBeginElse( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), withInputs: [signatureDef], types: [.wasmTypeDef()]) elseBody(elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) @@ -4058,53 +4749,81 @@ public class ProgramBuilder { // TODO(mliedtke): Instead of taking a WasmSignature also allow taking an existing signature // definition (Variable) as input and add a code generator for it. @discardableResult - public func wasmBuildIfElseWithResult(_ condition: Variable, hint: WasmBranchHint = .None, signature: WasmSignature, args: [Variable], ifBody: (Variable, [Variable]) -> [Variable], elseBody: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildIfElseWithResult( + _ condition: Variable, hint: WasmBranchHint = .None, signature: WasmSignature, + args: [Variable], ifBody: (Variable, [Variable]) -> [Variable], + elseBody: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let beginBlock = b.emit( WasmBeginIf(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args + [condition], types: [.wasmTypeDef()] + signature.parameterTypes + [.wasmi32]) - let trueResults = ifBody(beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) + let trueResults = ifBody( + beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) let elseBlock = b.emit( - WasmBeginElse(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), + WasmBeginElse( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), withInputs: [signatureDef] + trueResults, types: [.wasmTypeDef()] + signature.outputTypes) - let falseResults = elseBody(elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) - return Array(b.emit( - WasmEndIf(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + falseResults, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + let falseResults = elseBody( + elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) + return Array( + b.emit( + WasmEndIf(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + falseResults, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } @discardableResult - public func wasmBuildLoop(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildLoop( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - return wasmBuildLoopImpl(signature: signature, signatureDef: signatureDef, args: args, body: body) + return wasmBuildLoopImpl( + signature: signature, signatureDef: signatureDef, args: args, body: body) } // TODO(mliedtke): Also use this inside the code generator. @discardableResult - public func wasmBuildLoop(with signatureDef: Variable, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildLoop( + with signatureDef: Variable, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature - return wasmBuildLoopImpl(signature: signature, signatureDef: signatureDef, args: args, body: body) + return wasmBuildLoopImpl( + signature: signature, signatureDef: signatureDef, args: args, body: body) } - private func wasmBuildLoopImpl(signature: WasmSignature, signatureDef: Variable, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - let instr = b.emit(WasmBeginLoop(with: signature), withInputs: [signatureDef] + args, + private func wasmBuildLoopImpl( + signature: WasmSignature, signatureDef: Variable, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { + let instr = b.emit( + WasmBeginLoop(with: signature), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let fallthroughResults = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndLoop(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + fallthroughResults, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + return Array( + b.emit( + WasmEndLoop(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + fallthroughResults, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } // TODO(pawkra): enable shared types. @discardableResult - func wasmBuildTryTable(with signature: WasmSignature, args: [Variable], catches: [WasmBeginTryTable.CatchKind], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - assert(zip(signature.parameterTypes, args).allSatisfy {b.type(of: $1).Is($0)}) + func wasmBuildTryTable( + with signature: WasmSignature, args: [Variable], catches: [WasmBeginTryTable.CatchKind], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { + assert(zip(signature.parameterTypes, args).allSatisfy { b.type(of: $1).Is($0) }) #if DEBUG var argIndex = signature.parameterTypes.count - let assertLabelTypeData: (ILType) -> () = { labelType in + let assertLabelTypeData: (ILType) -> Void = { labelType in assert(labelType.Is(.anyLabel)) assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef())) } @@ -4134,16 +4853,20 @@ public class ProgramBuilder { WasmBeginTryTable(parameterCount: signature.parameterTypes.count, catches: catches), withInputs: [signatureDef] + args) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndTryTable(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + results).outputs) + return Array( + b.emit( + WasmEndTryTable(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + results + ).outputs) } // Create a legacy try-catch with a void block signature. Mostly a convenience helper for // test cases. public func wasmBuildLegacyTryVoid( - body: (Variable) -> Void, - catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> Void)] = [], - catchAllBody: ((Variable) -> Void)? = nil) { + body: (Variable) -> Void, + catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> Void)] = [], + catchAllBody: ((Variable) -> Void)? = nil + ) { let signature = [] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) @@ -4152,26 +4875,34 @@ public class ProgramBuilder { // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc // signature. let tagSignatures = catchClauses.map { - b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + b.wasmDefineAdHocSignatureType( + signature: b.type(of: $0.tag).wasmTagType!.parameters => []) } - let instr = b.emit(WasmBeginTry( - parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) + let instr = b.emit( + WasmBeginTry( + parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) assert(instr.innerOutputs.count == 1) body(instr.innerOutput(0)) for (i, (tag, generator)) in catchClauses.enumerated() { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + b.reportErrorIf( + !b.type(of: tag).isWasmTagType, + "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag))." + ) let tagSignatureDef = tagSignatures[i] - let instr = b.emit(WasmBeginCatch( + let instr = b.emit( + WasmBeginCatch( blockOutputCount: signature.outputTypes.count, - labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), withInputs: [signatureDef, tag, tagSignatureDef], - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) - generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + + signature.outputTypes) + generator( + instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody { - let instr = b.emit(WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef]) + let instr = b.emit( + WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef]) catchAllBody(instr.innerOutput(0)) } b.emit(WasmEndTry(blockOutputCount: 0), withInputs: [signatureDef]) @@ -4182,12 +4913,14 @@ public class ProgramBuilder { // tag arguments. @discardableResult public func wasmBuildLegacyTryWithResult( - signature: WasmSignature, - signatureDef: Variable, - args: [Variable], - body: (Variable, [Variable]) -> [Variable], - catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = [], - catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] { + signature: WasmSignature, + signatureDef: Variable, + args: [Variable], + body: (Variable, [Variable]) -> [Variable], + catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = + [], + catchAllBody: ((Variable) -> [Variable])? = nil + ) -> [Variable] { let parameterCount = signature.parameterTypes.count // Define tag signatures before the try block so they don't interfere with the try/catch @@ -4195,38 +4928,51 @@ public class ProgramBuilder { // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc // signature. let tagSignatures = catchClauses.map { - b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + b.wasmDefineAdHocSignatureType( + signature: b.type(of: $0.tag).wasmTagType!.parameters => []) } - let instr = b.emit(WasmBeginTry(parameterCount: parameterCount), + let instr = b.emit( + WasmBeginTry(parameterCount: parameterCount), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) var result = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) for (i, (tag, generator)) in catchClauses.enumerated() { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + b.reportErrorIf( + !b.type(of: tag).isWasmTagType, + "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag))." + ) let tagSignatureDef = tagSignatures[i] - let instr = b.emit(WasmBeginCatch( + let instr = b.emit( + WasmBeginCatch( blockOutputCount: signature.outputTypes.count, - labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), withInputs: [signatureDef, tag, tagSignatureDef] + result, - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) - result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + + signature.outputTypes) + result = generator( + instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody = catchAllBody { - let instr = b.emit(WasmBeginCatchAll(blockOutputCount: signature.outputTypes.count), + let instr = b.emit( + WasmBeginCatchAll(blockOutputCount: signature.outputTypes.count), withInputs: [signatureDef] + result, types: [.wasmTypeDef()] + signature.outputTypes) result = catchAllBody(instr.innerOutput(0)) } - return Array(b.emit(WasmEndTry(blockOutputCount: signature.outputTypes.count), - withInputs: [signatureDef] + result, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + return Array( + b.emit( + WasmEndTry(blockOutputCount: signature.outputTypes.count), + withInputs: [signatureDef] + result, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } public func WasmBuildThrow(tag: Variable, inputs: [Variable]) { let tagType = b.type(of: tag).wasmType as! WasmTagType - b.emit(WasmThrow(parameterCount: tagType.parameters.count), withInputs: [tag] + inputs, types: [.object(ofGroup: "WasmTag")] + tagType.parameters) + b.emit( + WasmThrow(parameterCount: tagType.parameters.count), withInputs: [tag] + inputs, + types: [.object(ofGroup: "WasmTag")] + tagType.parameters) } public func wasmBuildThrowRef(exception: Variable) { @@ -4237,10 +4983,14 @@ public class ProgramBuilder { b.emit(WasmRethrow(), withInputs: [exceptionLabel], types: [.exceptionLabel]) } - public func wasmBuildLegacyTryDelegate(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, delegate: Variable) { + public func wasmBuildLegacyTryDelegate( + with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, + delegate: Variable + ) { assert(signature.outputTypes.isEmpty) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), + let instr = b.emit( + WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) @@ -4248,16 +4998,22 @@ public class ProgramBuilder { } @discardableResult - public func wasmBuildLegacyTryDelegateWithResult(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable], delegate: Variable) -> [Variable] { + public func wasmBuildLegacyTryDelegateWithResult( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable], delegate: Variable + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), + let instr = b.emit( + WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndTryDelegate(outputCount: signature.outputTypes.count), - withInputs: [signatureDef, delegate] + results, - types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes - ).outputs) + return Array( + b.emit( + WasmEndTryDelegate(outputCount: signature.outputTypes.count), + withInputs: [signatureDef, delegate] + results, + types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes + ).outputs) } public func generateRandomWasmVar(ofType type: ILType) -> Variable? { @@ -4271,7 +5027,8 @@ public class ProgramBuilder { case .wasmf64: return self.constf64(b.randomFloat()) case .wasmSimd128: - return self.constSimd128(value: (0 ..< 16).map{ _ in UInt8.random(in: UInt8.min ... UInt8.max) }) + return self.constSimd128( + value: (0..<16).map { _ in UInt8.random(in: UInt8.min...UInt8.max) }) default: if type.Is(.wasmGenericRef) { // TODO(cffsmith): Can we improve this once we have better support for ad hoc @@ -4285,14 +5042,15 @@ public class ProgramBuilder { } // Prefer generating a non-null value. if heapTypeInfo.heapType == .WasmI31 { - return self.wasmRefI31(self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) + return self.wasmRefI31( + self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) } // TODO(pawkra): support other non-nullable types. - if (type.wasmReferenceType!.nullability) { + if type.wasmReferenceType!.nullability { return self.wasmRefNull(type: type) } case .Index(_): - if (type.wasmReferenceType?.nullability ?? false) { + if type.wasmReferenceType?.nullability ?? false { return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) } case .none: @@ -4315,17 +5073,26 @@ public class ProgramBuilder { } @discardableResult - public func wasmSelect(on condition: Variable, trueValue: Variable, falseValue: Variable) -> Variable { + public func wasmSelect(on condition: Variable, trueValue: Variable, falseValue: Variable) + -> Variable + { let lhsType = b.type(of: trueValue) - return b.emit(WasmSelect(), withInputs: [trueValue, falseValue, condition], types: [lhsType, lhsType, .wasmi32]).output + return b.emit( + WasmSelect(), withInputs: [trueValue, falseValue, condition], + types: [lhsType, lhsType, .wasmi32] + ).output } public func wasmReturn(_ values: [Variable]) { - b.emit(WasmReturn(returnCount: values.count), withInputs: values, types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: values.count), withInputs: values, + types: signature.outputTypes) } public func wasmReturn(_ returnVariable: Variable) { - b.emit(WasmReturn(returnCount: 1), withInputs: [returnVariable], types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: 1), withInputs: [returnVariable], + types: signature.outputTypes) } public func wasmReturn() { @@ -4339,45 +5106,87 @@ public class ProgramBuilder { } @discardableResult - public func wasmSimd128IntegerUnOp(_ input: Variable, _ shape: WasmSimd128Shape, _ integerUnOpKind: WasmSimd128IntegerUnOpKind) -> Variable { - return b.emit(WasmSimd128IntegerUnOp(shape: shape, unOpKind: integerUnOpKind), withInputs: [input], types: [.wasmSimd128]).output + public func wasmSimd128IntegerUnOp( + _ input: Variable, _ shape: WasmSimd128Shape, + _ integerUnOpKind: WasmSimd128IntegerUnOpKind + ) -> Variable { + return b.emit( + WasmSimd128IntegerUnOp(shape: shape, unOpKind: integerUnOpKind), + withInputs: [input], types: [.wasmSimd128] + ).output } @discardableResult - public func wasmSimd128IntegerBinOp(_ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ integerBinOpKind: WasmSimd128IntegerBinOpKind) -> Variable { + public func wasmSimd128IntegerBinOp( + _ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ integerBinOpKind: WasmSimd128IntegerBinOpKind + ) -> Variable { // Shifts take an i32 as an rhs input, the others take a regular .wasmSimd128 input. - let rhsInputType: ILType = switch integerBinOpKind { - case .shl, .shr_s, .shr_u: - .wasmi32 - default: - .wasmSimd128 - } - return b.emit(WasmSimd128IntegerBinOp(shape: shape, binOpKind: integerBinOpKind), withInputs: [left, right], types: [.wasmSimd128, rhsInputType]).output + let rhsInputType: ILType = + switch integerBinOpKind { + case .shl, .shr_s, .shr_u: + .wasmi32 + default: + .wasmSimd128 + } + return b.emit( + WasmSimd128IntegerBinOp(shape: shape, binOpKind: integerBinOpKind), + withInputs: [left, right], types: [.wasmSimd128, rhsInputType] + ).output } @discardableResult - public func wasmSimd128IntegerTernaryOp(_ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ integerTernaryOpKind: WasmSimd128IntegerTernaryOpKind) -> Variable { - return b.emit(WasmSimd128IntegerTernaryOp(shape: shape, ternaryOpKind: integerTernaryOpKind), withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128]).output + public func wasmSimd128IntegerTernaryOp( + _ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ integerTernaryOpKind: WasmSimd128IntegerTernaryOpKind + ) -> Variable { + return b.emit( + WasmSimd128IntegerTernaryOp(shape: shape, ternaryOpKind: integerTernaryOpKind), + withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatUnOp(_ input: Variable, _ shape: WasmSimd128Shape, _ floatUnOpKind: WasmSimd128FloatUnOpKind) -> Variable { - return b.emit(WasmSimd128FloatUnOp(shape: shape, unOpKind: floatUnOpKind), withInputs: [input], types: [.wasmSimd128]).output + public func wasmSimd128FloatUnOp( + _ input: Variable, _ shape: WasmSimd128Shape, _ floatUnOpKind: WasmSimd128FloatUnOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatUnOp(shape: shape, unOpKind: floatUnOpKind), withInputs: [input], + types: [.wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatBinOp(_ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ floatBinOpKind: WasmSimd128FloatBinOpKind) -> Variable { - return b.emit(WasmSimd128FloatBinOp(shape: shape, binOpKind: floatBinOpKind), withInputs: [left, right], types: [.wasmSimd128, .wasmSimd128]).output + public func wasmSimd128FloatBinOp( + _ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ floatBinOpKind: WasmSimd128FloatBinOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatBinOp(shape: shape, binOpKind: floatBinOpKind), + withInputs: [left, right], types: [.wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatTernaryOp(_ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ floatTernaryOpKind: WasmSimd128FloatTernaryOpKind) -> Variable { - return b.emit(WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: floatTernaryOpKind), withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128]).output + public func wasmSimd128FloatTernaryOp( + _ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ floatTernaryOpKind: WasmSimd128FloatTernaryOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: floatTernaryOpKind), + withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128Compare(_ lhs: Variable, _ rhs: Variable, _ shape: WasmSimd128Shape, _ compareOpKind: WasmSimd128CompareOpKind) -> Variable { - return b.emit(WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind), withInputs: [lhs, rhs], types: [.wasmSimd128, .wasmSimd128]).output + public func wasmSimd128Compare( + _ lhs: Variable, _ rhs: Variable, _ shape: WasmSimd128Shape, + _ compareOpKind: WasmSimd128CompareOpKind + ) -> Variable { + return b.emit( + WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind), + withInputs: [lhs, rhs], types: [.wasmSimd128, .wasmSimd128] + ).output } @discardableResult @@ -4386,47 +5195,72 @@ public class ProgramBuilder { } @discardableResult - func wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind, _ input: Variable, _ lane: Int) -> Variable { - return b.emit(WasmSimdExtractLane(kind: kind, lane: lane), withInputs: [input], types: [.wasmSimd128]).output + func wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind, _ input: Variable, _ lane: Int) + -> Variable + { + return b.emit( + WasmSimdExtractLane(kind: kind, lane: lane), withInputs: [input], + types: [.wasmSimd128] + ).output } @discardableResult - func wasmSimdReplaceLane(kind: WasmSimdReplaceLane.Kind, _ input: Variable, _ laneValue: Variable, _ lane: Int) -> Variable { - return b.emit(WasmSimdReplaceLane(kind: kind, lane: lane), - withInputs: [input, laneValue], types: [.wasmSimd128, kind.laneType()]).output - } - - func wasmSimdStoreLane(kind: WasmSimdStoreLane.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64, from: Variable, lane: Int) { + func wasmSimdReplaceLane( + kind: WasmSimdReplaceLane.Kind, _ input: Variable, _ laneValue: Variable, _ lane: Int + ) -> Variable { + return b.emit( + WasmSimdReplaceLane(kind: kind, lane: lane), + withInputs: [input, laneValue], types: [.wasmSimd128, kind.laneType()] + ).output + } + + func wasmSimdStoreLane( + kind: WasmSimdStoreLane.Kind, memory: Variable, dynamicOffset: Variable, + staticOffset: Int64, from: Variable, lane: Int + ) { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmSimdStoreLane(kind: kind, staticOffset: staticOffset, lane: lane), + b.emit( + WasmSimdStoreLane(kind: kind, staticOffset: staticOffset, lane: lane), withInputs: [memory, dynamicOffset, from], types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128]) } @discardableResult - func wasmSimdLoadLane(kind: WasmSimdLoadLane.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64, into: Variable, lane: Int) -> Variable { + func wasmSimdLoadLane( + kind: WasmSimdLoadLane.Kind, memory: Variable, dynamicOffset: Variable, + staticOffset: Int64, into: Variable, lane: Int + ) -> Variable { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmSimdLoadLane(kind: kind, staticOffset: staticOffset, lane: lane), + return b.emit( + WasmSimdLoadLane(kind: kind, staticOffset: staticOffset, lane: lane), withInputs: [memory, dynamicOffset, into], - types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128]).output + types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128] + ).output } @discardableResult - func wasmSimdLoad(kind: WasmSimdLoad.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64) -> Variable { + func wasmSimdLoad( + kind: WasmSimdLoad.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64 + ) -> Variable { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmSimdLoad(kind: kind, staticOffset: staticOffset), + return b.emit( + WasmSimdLoad(kind: kind, staticOffset: staticOffset), withInputs: [memory, dynamicOffset], - types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType]).output + types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType] + ).output } @discardableResult public func wasmArrayNewFixed(arrayType: Variable, elements: [Variable]) -> Variable { let arrayDesc = b.jsTyper.getTypeDescription(of: arrayType) as! WasmArrayTypeDescription - assert(elements.allSatisfy {b.jsTyper.type(of: $0).Is(arrayDesc.elementType.unpacked())}) - return b.emit(WasmArrayNewFixed(size: elements.count), withInputs: [arrayType] + elements).output + assert( + elements.allSatisfy { b.jsTyper.type(of: $0).Is(arrayDesc.elementType.unpacked()) }) + return b.emit( + WasmArrayNewFixed(size: elements.count), withInputs: [arrayType] + elements + ).output } @discardableResult @@ -4440,21 +5274,28 @@ public class ProgramBuilder { } @discardableResult - public func wasmArrayGet(array: Variable, index: Variable, isSigned: Bool = false) -> Variable { - return b.emit(WasmArrayGet(isSigned: isSigned), withInputs: [array, index], - types: [.wasmGenericRef, .wasmi32]).output + public func wasmArrayGet(array: Variable, index: Variable, isSigned: Bool = false) + -> Variable + { + return b.emit( + WasmArrayGet(isSigned: isSigned), withInputs: [array, index], + types: [.wasmGenericRef, .wasmi32] + ).output } public func wasmArraySet(array: Variable, index: Variable, element: Variable) { let arrayDesc = b.jsTyper.getTypeDescription(of: array) as! WasmArrayTypeDescription assert(arrayDesc.mutability) - b.emit(WasmArraySet(), withInputs: [array, index, element], - types: [.wasmGenericRef, .wasmi32, arrayDesc.elementType.unpacked()]) + b.emit( + WasmArraySet(), withInputs: [array, index, element], + types: [.wasmGenericRef, .wasmi32, arrayDesc.elementType.unpacked()]) } @discardableResult public func wasmStructNew(structType: Variable, fields: [Variable]) -> Variable { - return b.emit(WasmStructNew(fieldCount: fields.count), withInputs: [structType] + fields).output + return b.emit( + WasmStructNew(fieldCount: fields.count), withInputs: [structType] + fields + ).output } @discardableResult @@ -4463,12 +5304,17 @@ public class ProgramBuilder { } @discardableResult - public func wasmStructGet(theStruct: Variable, fieldIndex: Int, isSigned: Bool = false) -> Variable { - return b.emit(WasmStructGet(fieldIndex: fieldIndex, isSigned: isSigned), withInputs: [theStruct]).output + public func wasmStructGet(theStruct: Variable, fieldIndex: Int, isSigned: Bool = false) + -> Variable + { + return b.emit( + WasmStructGet(fieldIndex: fieldIndex, isSigned: isSigned), withInputs: [theStruct] + ).output } public func wasmStructSet(theStruct: Variable, fieldIndex: Int, value: Variable) { - let structDesc = b.jsTyper.getTypeDescription(of: theStruct) as! WasmStructTypeDescription + let structDesc = + b.jsTyper.getTypeDescription(of: theStruct) as! WasmStructTypeDescription assert(structDesc.fields[fieldIndex].mutability) b.emit(WasmStructSet(fieldIndex: fieldIndex), withInputs: [theStruct, value]) } @@ -4476,7 +5322,8 @@ public class ProgramBuilder { @discardableResult public func wasmRefNull(type: ILType) -> Variable { assert(type.isWasmReferenceType) - assert(type.wasmReferenceType!.isAbstract(), "index types must use .wasmRefNull(Variable)") + assert( + type.wasmReferenceType!.isAbstract(), "index types must use .wasmRefNull(Variable)") return b.emit(WasmRefNull(type: type)).output } @@ -4493,12 +5340,15 @@ public class ProgramBuilder { @discardableResult // TODO(pawkra): Support shared references. public func wasmRefEq(_ lhs: Variable, _ rhs: Variable) -> Variable { - return b.emit(WasmRefEq(), withInputs: [lhs, rhs], types: [.wasmEqRef(), .wasmEqRef()]).output + return b.emit( + WasmRefEq(), withInputs: [lhs, rhs], types: [.wasmEqRef(), .wasmEqRef()] + ).output } @discardableResult public func wasmRefI31(_ number: Variable, shared: Bool = false) -> Variable { - return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]).output + return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]) + .output } @discardableResult @@ -4517,16 +5367,22 @@ public class ProgramBuilder { } @discardableResult - public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { + public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) + -> Variable + { let inputs = typeDef == nil ? [ref] : [ref, typeDef!] - let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] + let types: [ILType] = + typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] return b.emit(WasmRefTest(refType: refType), withInputs: inputs, types: types).output } @discardableResult - public func wasmRefCast(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { + public func wasmRefCast(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) + -> Variable + { let inputs = typeDef == nil ? [ref] : [ref, typeDef!] - let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] + let types: [ILType] = + typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] return b.emit(WasmRefCast(refType: refType), withInputs: inputs, types: types).output } @@ -4577,17 +5433,29 @@ public class ProgramBuilder { // TODO: distinguish between exported and non-exported functions @discardableResult - public func addWasmFunction(with signature: WasmSignature, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + public func addWasmFunction( + with signature: WasmSignature, + _ body: (WasmFunction, Variable, [Variable]) -> [Variable] + ) -> Variable { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) return addWasmFunction(signature: signatureDef, body) } @discardableResult - public func addWasmFunction(signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + public func addWasmFunction( + signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable] + ) -> Variable { let signatureType = b.type(of: signature).wasmFunctionSignatureDefSignature - let instr = b.emit(BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), withInputs: [signature]) - let results = body(currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return b.emit(EndWasmFunction(outputCount: signatureType.outputTypes.count), withInputs: [signature] + results, types: [.wasmTypeDef()] + signatureType.outputTypes).output + let instr = b.emit( + BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), + withInputs: [signature]) + let results = body( + currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) + return b.emit( + EndWasmFunction(outputCount: signatureType.outputTypes.count), + withInputs: [signature] + results, + types: [.wasmTypeDef()] + signatureType.outputTypes + ).output } @discardableResult @@ -4596,34 +5464,54 @@ public class ProgramBuilder { } @discardableResult - public func addTable(elementType: ILType, minSize: Int, maxSize: Int? = nil, definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [], definedEntryValues: [Variable] = [], isTable64: Bool) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: elementType), count: definedEntries.count) - return b.emit(WasmDefineTable(elementType: elementType, limits: Limits(min: minSize, max: maxSize), definedEntries: definedEntries, isTable64: isTable64), - withInputs: definedEntryValues, types: inputTypes).output + public func addTable( + elementType: ILType, minSize: Int, maxSize: Int? = nil, + definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [], + definedEntryValues: [Variable] = [], isTable64: Bool + ) -> Variable { + let inputTypes = Array( + repeating: getEntryTypeForTable(elementType: elementType), + count: definedEntries.count) + return b.emit( + WasmDefineTable( + elementType: elementType, limits: Limits(min: minSize, max: maxSize), + definedEntries: definedEntries, isTable64: isTable64), + withInputs: definedEntryValues, types: inputTypes + ).output } @discardableResult public func addElementSegment(elements: [Variable]) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef()), count: elements.count) - return b.emit(WasmDefineElementSegment(size: UInt32(elements.count)), withInputs: elements, types: inputTypes).output + let inputTypes = Array( + repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef()), + count: elements.count) + return b.emit( + WasmDefineElementSegment(size: UInt32(elements.count)), withInputs: elements, + types: inputTypes + ).output } // TODO(pawkra): support tables of shared elements. public func getEntryTypeForTable(elementType: ILType) -> ILType { switch elementType { - case .wasmFuncRef(): - return .wasmFunctionDef() | .function() - default: - return .object() + case .wasmFuncRef(): + return .wasmFunctionDef() | .function() + default: + return .object() } } - // This result can be ignored right now, as we can only define one memory per module // Also this should be tracked like a global / table. @discardableResult - public func addMemory(minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false) -> Variable { - return b.emit(WasmDefineMemory(limits: Limits(min: minPages, max: maxPages), isShared: isShared, isMemory64: isMemory64)).output + public func addMemory( + minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false + ) -> Variable { + return b.emit( + WasmDefineMemory( + limits: Limits(min: minPages, max: maxPages), isShared: isShared, + isMemory64: isMemory64) + ).output } @discardableResult @@ -4669,7 +5557,9 @@ public class ProgramBuilder { // (dynamicOffset + alignedStaticOffset) % alignment == 0 // // Note: In rare cases, the returned values may lead to an out-of-bounds memory access. - func generateAlignedMemoryIndexes(forMemory memory: Variable, alignment: Int64) -> (address: Variable, offset: Int64) { + func generateAlignedMemoryIndexes(forMemory memory: Variable, alignment: Int64) -> ( + address: Variable, offset: Int64 + ) { assert(alignment > 0, "Alignment must be positive") let memoryTypeInfo = self.type(of: memory).wasmMemoryType! let memSize = Int64(memoryTypeInfo.limits.min * WasmConstants.specWasmMemPageSize) @@ -4683,7 +5573,8 @@ public class ProgramBuilder { // The '+1' allows out-of-bounds access (dynamicOffset + alignedStaticOffset == memSize) let dynamicOffsetValue = self.randomNonNegativeIndex(upTo: memSize - alignment + 1) let dynamicOffset = function.memoryArgument(dynamicOffsetValue, memoryTypeInfo) - let staticOffset = self.randomNonNegativeIndex(upTo: memSize - alignment + 1 - dynamicOffsetValue) + let staticOffset = self.randomNonNegativeIndex( + upTo: memSize - alignment + 1 - dynamicOffsetValue) let currentAddress = dynamicOffsetValue + staticOffset // Calculate the minimal value needed to make the total address aligned. @@ -4692,7 +5583,9 @@ public class ProgramBuilder { return (dynamicOffset, alignedStaticOffset) } - func generateRandomWasmStructFields() -> (fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) { + func generateRandomWasmStructFields() -> ( + fields: [WasmStructTypeDescription.Field], indexTypes: [Variable] + ) { var indexTypes: [Variable] = [] let fields = (0.. WasmSignature { @@ -4769,13 +5670,14 @@ public class ProgramBuilder { chooseUniform( from: chooseBiased(from: [nullTypes, abstractRefTypes, valueTypes], factor: 1.5)) } - let returnTypes: [ILType] = (0.. returnTypes } public func randomWasmGcSignature(withResults: Bool = true, allowNonNullable: Bool = true) - -> (signature: WasmSignature, indexTypes: [Variable]) { + -> (signature: WasmSignature, indexTypes: [Variable]) + { let typeCount = Int.random(in: 0...10) let returnCount = withResults ? Int.random(in: 0...typeCount) : 0 let parameterCount = typeCount - returnCount @@ -4783,19 +5685,24 @@ public class ProgramBuilder { var indexTypes: [Variable] = [] let chooseType = { if let elementType = self.randomVariable(ofType: .wasmTypeDef()), probability(0.25) { - let nullability = !allowNonNullable + let nullability = + !allowNonNullable || self.type(of: elementType).wasmTypeDefinition!.description == .selfReference || probability(0.5) indexTypes.append(elementType) return ILType.wasmRef(.Index(), nullability: nullability) } else { let nullability = !allowNonNullable || probability(0.5) - return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128] - + WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: nullability)}) + return chooseUniform( + from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128] + + WasmAbstractHeapType.allCases.map { + ILType.wasmRef($0, nullability: nullability) + }) } } - let signature = (0.. (0.. (0.. [Variable] { - (0.. WasmBranchHint { @@ -4828,10 +5740,12 @@ public class ProgramBuilder { } else { if shape == .i64x2 { // i64x2 does not provide unsigned comparison. - return .iKind(value: - chooseUniform(from: WasmIntegerCompareOpKind.allCases.filter{ - return $0 != .Lt_u && $0 != .Le_u && $0 != .Gt_u && $0 != .Ge_u - })) + return .iKind( + value: + chooseUniform( + from: WasmIntegerCompareOpKind.allCases.filter { + return $0 != .Lt_u && $0 != .Le_u && $0 != .Gt_u && $0 != .Ge_u + })) } else { return .iKind(value: chooseUniform(from: WasmIntegerCompareOpKind.allCases)) } @@ -4839,7 +5753,7 @@ public class ProgramBuilder { } @discardableResult - public func buildWasmModule(_ body: (WasmModule) -> ()) -> WasmModule { + public func buildWasmModule(_ body: (WasmModule) -> Void) -> WasmModule { emit(BeginWasmModule()) let module = self.currentWasmModule body(module) @@ -4856,7 +5770,7 @@ public class ProgramBuilder { } @discardableResult - public func wasmDefineTypeGroup(recursiveGenerator: () -> ()) -> [Variable] { + public func wasmDefineTypeGroup(recursiveGenerator: () -> Void) -> [Variable] { emit(WasmBeginTypeGroup()) recursiveGenerator() return wasmEndTypeGroup() @@ -4882,33 +5796,48 @@ public class ProgramBuilder { /// This takes a signature with resolved index types for ease-of-use (meaning it accepts full /// index reference types directly inside the signature). @discardableResult - func wasmDefineAdHocSignatureType(signature: WasmSignature, indexTypes: [Variable]? = nil) -> Variable { - let indexTypes = indexTypes ?? (signature.parameterTypes + signature.outputTypes) - .filter {$0.Is(.anyIndexRef)} - .map(getWasmTypeDef) - let cleanIndexTypes = {(type: ILType) -> ILType in + func wasmDefineAdHocSignatureType(signature: WasmSignature, indexTypes: [Variable]? = nil) + -> Variable + { + let indexTypes = + indexTypes + ?? (signature.parameterTypes + signature.outputTypes) + .filter { $0.Is(.anyIndexRef) } + .map(getWasmTypeDef) + let cleanIndexTypes = { (type: ILType) -> ILType in type.Is(.anyIndexRef) ? .wasmRef(.Index(), nullability: type.wasmReferenceType!.nullability) : type } - let signature = signature.parameterTypes.map(cleanIndexTypes) + let signature = + signature.parameterTypes.map(cleanIndexTypes) => signature.outputTypes.map(cleanIndexTypes) if context.contains(.wasmFunction) { - return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes).output + return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes) + .output } else { assert(context.contains(.wasm)) - return emit(WasmDefineAdHocModuleSignatureType(signature: signature), withInputs: indexTypes).output + return emit( + WasmDefineAdHocModuleSignatureType(signature: signature), withInputs: indexTypes + ).output } } @discardableResult - func wasmDefineArrayType(elementType: ILType, mutability: Bool, indexType: Variable? = nil) -> Variable { + func wasmDefineArrayType(elementType: ILType, mutability: Bool, indexType: Variable? = nil) + -> Variable + { let inputs = indexType != nil ? [indexType!] : [] - return emit(WasmDefineArrayType(elementType: elementType, mutability: mutability), withInputs: inputs).output + return emit( + WasmDefineArrayType(elementType: elementType, mutability: mutability), + withInputs: inputs + ).output } @discardableResult - func wasmDefineStructType(fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) -> Variable { + func wasmDefineStructType(fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) + -> Variable + { return emit(WasmDefineStructType(fields: fields), withInputs: indexTypes).output } @@ -4923,20 +5852,25 @@ public class ProgramBuilder { } // Converts an array to a string separating elements by comma. This is used for testing only. func arrayToStringForTesting(_ array: Variable) -> Variable { - let stringified = callMethod("map", on: array, - withArgs: [buildArrowFunction(with: .parameters(n: 1)) { args in - doReturn(callMethod("toString", on: args[0])) - }]) + let stringified = callMethod( + "map", on: array, + withArgs: [ + buildArrowFunction(with: .parameters(n: 1)) { args in + doReturn(callMethod("toString", on: args[0])) + } + ]) return callMethod("join", on: stringified, withArgs: [loadString(",")]) } - func wasmDefineAndResolveForwardReference(recursiveGenerator: () -> ()) { - let previousTypes = Set(scopes.elementsStartingAtTop().joined().filter {type(of: $0).Is(.wasmTypeDef())}) + func wasmDefineAndResolveForwardReference(recursiveGenerator: () -> Void) { + let previousTypes = Set( + scopes.elementsStartingAtTop().joined().filter { type(of: $0).Is(.wasmTypeDef()) }) let ref = wasmDefineForwardOrSelfReference() recursiveGenerator() let newTypes = scopes.elementsStartingAtTop().joined().filter { let t = type(of: $0) - return !previousTypes.contains($0) && t.Is(.wasmTypeDef()) && t.wasmTypeDefinition?.description != .selfReference + return !previousTypes.contains($0) && t.Is(.wasmTypeDef()) + && t.wasmTypeDefinition?.description != .selfReference } if !newTypes.isEmpty { wasmResolveForwardReference(ref, to: chooseUniform(from: newTypes)) @@ -5031,11 +5965,11 @@ public class ProgramBuilder { case .beginObjectLiteralComputedSetter: currentObjectLiteral.computedSetters.append(instr.input(0)) case .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter: + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter: break case .endObjectLiteral: activeObjectLiterals.pop() @@ -5128,21 +6062,22 @@ public class ProgramBuilder { case .endWasmFunction: activeWasmModule!.methods.append("w\(activeWasmModule!.methods.count)") case .wasmDefineGlobal(_), - .wasmDefineTable(_), - .wasmDefineMemory(_), - .wasmDefineDataSegment(_), - .wasmDefineElementSegment(_): + .wasmDefineTable(_), + .wasmDefineMemory(_), + .wasmDefineDataSegment(_), + .wasmDefineElementSegment(_): break case .wasmDefineTag(_): break case .beginWasmFunction(_): - activeWasmModule!.functions.append(WasmFunction(forBuilder: self, signatureDef: instr.input(0))) + activeWasmModule!.functions.append( + WasmFunction(forBuilder: self, signatureDef: instr.input(0))) case .wasmBeginTry(_), - .wasmEndTryDelegate(_), - .wasmBeginTryDelegate(_), - .wasmBeginTryTable(_), - .wasmEndTryTable(_), - .wasmDefineAdHocModuleSignatureType(_): + .wasmEndTryDelegate(_), + .wasmBeginTryDelegate(_), + .wasmBeginTryTable(_), + .wasmEndTryTable(_), + .wasmDefineAdHocModuleSignatureType(_): break default: @@ -5166,29 +6101,39 @@ public class ProgramBuilder { func createOptionsBag(_ bag: OptionsBag, predefined: [String: Variable] = [:]) -> Variable { // We run .filter() to pick a subset of fields, but we generally want to set as many as possible // and let the mutator prune things - let dict = [String : Variable](uniqueKeysWithValues: bag.properties.filter {_ in probability(0.8)}.map { - let (propertyName, type) = $0 - if let predefinedVar = predefined[propertyName] { - return (propertyName, predefinedVar) - } else if type.isEnumeration { - return (propertyName, loadEnum(type)) - // relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it - } else if type.Is(OptionsBag.jsTemporalRelativeTo) { - return (propertyName, findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime, - .jsTemporalPlainDate, .string]))) - } else { - return (propertyName, findOrGenerateType(type)) - } - }) + let dict = [String: Variable]( + uniqueKeysWithValues: bag.properties.filter { _ in probability(0.8) }.map { + let (propertyName, type) = $0 + if let predefinedVar = predefined[propertyName] { + return (propertyName, predefinedVar) + } else if type.isEnumeration { + return (propertyName, loadEnum(type)) + // relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it + } else if type.Is(OptionsBag.jsTemporalRelativeTo) { + return ( + propertyName, + findOrGenerateType( + chooseUniform(from: [ + .jsTemporalZonedDateTime, .jsTemporalPlainDateTime, + .jsTemporalPlainDate, .string, + ])) + ) + } else { + return (propertyName, findOrGenerateType(type)) + } + }) return createObject(with: dict) } // Generate a Temporal.Duration object @discardableResult func createTemporalDurationFieldsObject() -> Variable { - var properties: [String : Variable] = [:] + var properties: [String: Variable] = [:] // Durations are simple, they accept an object with optional integer fields for each duration field. - for field in ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"] { + for field in [ + "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", + "microseconds", "nanoseconds", + ] { if Bool.random() { properties[field] = randomVariable(forUseAs: .number) } @@ -5199,7 +6144,8 @@ public class ProgramBuilder { // Generate a random time zone identifier @discardableResult func randomTimeZone() -> Variable { - return loadString(ProgramBuilder.randomTimeZoneString(), customName: "TemporalTimeZoneString") + return loadString( + ProgramBuilder.randomTimeZoneString(), customName: "TemporalTimeZoneString") } @discardableResult @@ -5214,7 +6160,9 @@ public class ProgramBuilder { @discardableResult func randomUTCOffset(mayHaveSeconds: Bool) -> Variable { - return loadString(ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: mayHaveSeconds), customName: "TemporalTimeZoneString") + return loadString( + ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: mayHaveSeconds), + customName: "TemporalTimeZoneString") } @discardableResult @@ -5223,13 +6171,13 @@ public class ProgramBuilder { // Bias towards zero minutes since that's what most time zones do. let zeroMinutes = probability(0.8) let minutes = zeroMinutes ? 0 : Int.random(in: 0..<60) - let plusminus = Bool.random() ? "+" : "-"; + let plusminus = Bool.random() ? "+" : "-" var offset = String(format: "%@%02d:%02d", plusminus, hours, minutes) if !zeroMinutes && mayHaveSeconds && probability(0.3) { let seconds = Int.random(in: 0..<60) offset = String(format: "%@:%02d", offset, seconds) - if probability(0.3) { - offset = String(format: "%@:.%09d", offset, Int.random(in: 0...999999999)) + if probability(0.3) { + offset = String(format: "%@:.%09d", offset, Int.random(in: 0...999_999_999)) } } return offset @@ -5241,8 +6189,10 @@ public class ProgramBuilder { // with() will error when given a calendar; so we allow control over omitting // a `calendar` field. @discardableResult - func createTemporalFieldsObject(forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool) -> Variable { - var properties: [String : Variable] = [:] + func createTemporalFieldsObject( + forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool + ) -> Variable { + var properties: [String: Variable] = [:] if dateFields { var chosenCalendar: String? = nil @@ -5256,7 +6206,8 @@ public class ProgramBuilder { "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", "islamicc", "iso8601", "japanese", - "persian", "roc"]) + "persian", "roc", + ]) properties["calendar"] = loadString(chosenCalendar!) } @@ -5266,7 +6217,7 @@ public class ProgramBuilder { // If the "year" is set, reduce the chance of emitting an "eraYear" which in most cases // would contradict. - let eraProbability = properties["year"] == nil ? 0.8 : 0.2; + let eraProbability = properties["year"] == nil ? 0.8 : 0.2 if probability(eraProbability) { properties["eraYear"] = randomVariable(forUseAs: .integer) // https://tc39.es/proposal-intl-era-monthcode/#table-eras @@ -5274,7 +6225,8 @@ public class ProgramBuilder { let japaneseEras = ["reiwa", "heisei", "showa", "taisho", "meiji"] let rocEras = ["roc", "broc", "minguo", "before-roc", "minguo-qian"] // If we know the calendar, we should choose from the list of valid eras. - let eras = switch chosenCalendar { + let eras = + switch chosenCalendar { case "buddhist": ["be"] case "coptic": @@ -5294,12 +6246,12 @@ public class ProgramBuilder { case "roc": rocEras default: - ["be", "am", "aa", "mundi", "incar", "shaka", "ah", "bh", "ap"] + gregoryEras + japaneseEras + rocEras - } + ["be", "am", "aa", "mundi", "incar", "shaka", "ah", "bh", "ap"] + + gregoryEras + japaneseEras + rocEras + } properties["era"] = loadString(chooseUniform(from: eras)) } - if probability(0.8) { // Sometimes generates out of range values to test "constrain" // behavior. @@ -5308,7 +6260,7 @@ public class ProgramBuilder { // We don't wish to have clashing month/monthCode // *most* of the time, but we still wish to also test those codepaths. - let monthCodeProbability = properties["month"] == nil ? 0.8 : 0.2; + let monthCodeProbability = properties["month"] == nil ? 0.8 : 0.2 if probability(monthCodeProbability) { // Month codes go from M00 to M13. var code = String(format: "M%02d", Int.random(in: 0...13)) @@ -5359,7 +6311,7 @@ public class ProgramBuilder { // or the time zone first (and it's not a *useful* ambiguity). // Instead, you are expected to use `.with()` and `.withTimeZone()` // in whatever order you need. - if (!forWith) { + if !forWith { if Bool.random() { // Time zones can be offsets, but cannot have seconds generatedOffset = randomUTCOffset(mayHaveSeconds: false) @@ -5414,20 +6366,22 @@ public class ProgramBuilder { // Whether to pass a Temporal-like object or a string if Bool.random() { let fields = createTemporalDurationFieldsObject() - return callMethod("", on: constructor, withArgs: [ fields ] ) + return callMethod("", on: constructor, withArgs: [fields]) } else { // TODO(manishearth, 439921647) Generate Temporal-like strings let string = randomVariable(forUseAs: .string) return callMethod("from", on: constructor, withArgs: [string]) - } - } + } + } } // Generic generators for Temporal date/time types. // Pass in a closure that knows how to construct the type with `new()`. - private func constructTemporalType(type: String, - dateFields: Bool, timeFields: Bool, zonedFields: Bool, optionsBag: OptionsBag, - generateWithConstructor: (Variable) -> Variable) -> Variable { + private func constructTemporalType( + type: String, + dateFields: Bool, timeFields: Bool, zonedFields: Bool, optionsBag: OptionsBag, + generateWithConstructor: (Variable) -> Variable + ) -> Variable { let temporal = createNamedVariable(forBuiltin: "Temporal") let useConstructor = Bool.random() let constructor = getProperty(type, of: temporal) @@ -5436,12 +6390,14 @@ public class ProgramBuilder { } else { // Whether to pass a Temporal-like object or a string if Bool.random() { - let fields = createTemporalFieldsObject(forWith: false, dateFields: dateFields, timeFields: timeFields, zonedFields: zonedFields) + let fields = createTemporalFieldsObject( + forWith: false, dateFields: dateFields, timeFields: timeFields, + zonedFields: zonedFields) var args = [fields] if Bool.random() { args.append(createOptionsBag(optionsBag)) } - return callMethod("from", on: constructor, withArgs: args ) + return callMethod("from", on: constructor, withArgs: args) } else { // TODO(manishearth, 439921647) Generate Temporal-like strings let string = randomVariable(forUseAs: .string) @@ -5452,7 +6408,10 @@ public class ProgramBuilder { @discardableResult func constructTemporalTime() -> Variable { - return constructTemporalType(type: "PlainTime", dateFields: false, timeFields: true, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainTime", dateFields: false, timeFields: true, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes between 0 and 6 integer args. let numArgs = Int.random(in: 0...6) // Should we be constraining these to valid range? @@ -5463,9 +6422,12 @@ public class ProgramBuilder { @discardableResult func constructTemporalYearMonth() -> Variable { - return constructTemporalType(type: "PlainYearMonth", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainYearMonth", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args, an optional calendar, and an optional reference day. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) if Bool.random() { @@ -5477,9 +6439,12 @@ public class ProgramBuilder { } @discardableResult func constructTemporalMonthDay() -> Variable { - return constructTemporalType(type: "PlainMonthDay", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainMonthDay", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args, an optional calendar, and an optional reference day. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) if Bool.random() { @@ -5492,9 +6457,12 @@ public class ProgramBuilder { @discardableResult func constructTemporalDate() -> Variable { - return constructTemporalType(type: "PlainDate", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainDate", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args and an optional calendar. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) } @@ -5503,7 +6471,10 @@ public class ProgramBuilder { } @discardableResult func constructTemporalDateTime() -> Variable { - return constructTemporalType(type: "PlainDateTime", dateFields: true, timeFields: true, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainDateTime", dateFields: true, timeFields: true, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 mandatory integer args and between 0 and 6 additional integer args. let timeArgs = Int.random(in: 0...6) let totalIntArgs = 3 + timeArgs @@ -5517,7 +6488,10 @@ public class ProgramBuilder { @discardableResult func constructTemporalZonedDateTime() -> Variable { - return constructTemporalType(type: "ZonedDateTime", dateFields: true, timeFields: true, zonedFields: true, optionsBag: .jsTemporalZonedInterpretationSettings) { constructor in + return constructTemporalType( + type: "ZonedDateTime", dateFields: true, timeFields: true, zonedFields: true, + optionsBag: .jsTemporalZonedInterpretationSettings + ) { constructor in // The constructor takes one integer arg, one timezone arg, one optional calendar arg. // TODO(manishearth, 439921647) Generate timezone strings var args = [randomVariable(forUseAs: .bigint), randomVariable(forUseAs: .string)] @@ -5534,7 +6508,6 @@ public class ProgramBuilder { return constructIntlLanguageString() } - @discardableResult static func constructIntlLanguageString() -> String { // TODO(Manishearth) Generate more interesting locales than just the builtins @@ -5542,10 +6515,39 @@ public class ProgramBuilder { } // Obtained by calling Intl.supportedValuesOf("unit") in a browser - fileprivate static let allUnits = ["acre", "bit", "byte", "celsius", "centimeter", "day", "degree", "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram", "kilometer", "liter", "megabit", "megabyte", "meter", "microsecond", "mile", "mile-scandinavian", "milliliter", "millimeter", "millisecond", "minute", "month", "nanosecond", "ounce", "percent", "petabyte", "pound", "second", "stone", "terabit", "terabyte", "week", "yard", "year"] + fileprivate static let allUnits = [ + "acre", "bit", "byte", "celsius", "centimeter", "day", "degree", "fahrenheit", + "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", "gram", "hectare", "hour", "inch", + "kilobit", "kilobyte", "kilogram", "kilometer", "liter", "megabit", "megabyte", "meter", + "microsecond", "mile", "mile-scandinavian", "milliliter", "millimeter", "millisecond", + "minute", "month", "nanosecond", "ounce", "percent", "petabyte", "pound", "second", "stone", + "terabit", "terabyte", "week", "yard", "year", + ] // https://en.wikipedia.org/wiki/ISO_15924#List_of_codes // Unfortunately this list grows over time, but constructIntlScript can at least randomly generate other four-char script codes - fileprivate static let allScripts = ["Adlm", "Afak", "Aghb", "Ahom", "Arab", "Aran", "Armi", "Armn", "Avst", "Bali", "Bamu", "Bass", "Batk", "Beng", "Berf", "Bhks", "Blis", "Bopo", "Brah", "Brai", "Bugi", "Buhd", "Cakm", "Cans", "Cari", "Cham", "Cher", "Chis", "Chrs", "Cirt", "Copt", "Cpmn", "Cprt", "Cyrl", "Cyrs", "Deva", "Diak", "Dogr", "Dsrt", "Dupl", "Egyd", "Egyh", "Egyp", "Elba", "Elym", "Ethi", "Gara", "Geok", "Geor", "Glag", "Gong", "Gonm", "Goth", "Gran", "Grek", "Gujr", "Gukh", "Guru", "Hanb", "Hang", "Hani", "Hano", "Hans", "Hant", "Hatr", "Hebr", "Hira", "Hluw", "Hmng", "Hmnp", "Hntl", "Hrkt", "Hung", "Inds", "Ital", "Jamo", "Java", "Jpan", "Jurc", "Kali", "Kana", "Kawi", "Khar", "Khmr", "Khoj", "Kitl", "Kits", "Knda", "Kore", "Kpel", "Krai", "Kthi", "Lana", "Laoo", "Latf", "Latg", "Latn", "Leke", "Lepc", "Limb", "Lina", "Linb", "Lisu", "Loma", "Lyci", "Lydi", "Mahj", "Maka", "Mand", "Mani", "Marc", "Maya", "Medf", "Mend", "Merc", "Mero", "Mlym", "Modi", "Mong", "Moon", "Mroo", "Mtei", "Mult", "Mymr", "Nagm", "Nand", "Narb", "Nbat", "Newa", "Nkdb", "Nkgb", "Nkoo", "Nshu", "Ogam", "Olck", "Onao", "Orkh", "Orya", "Osge", "Osma", "Ougr", "Palm", "Pauc", "Pcun", "Pelm", "Perm", "Phag", "Phli", "Phlp", "Phlv", "Phnx", "Piqd", "Plrd", "Prti", "Psin", "Qaaa-Qabx", "Ranj", "Rjng", "Rohg", "Roro", "Runr", "Samr", "Sara", "Sarb", "Saur", "Seal", "Sgnw", "Shaw", "Shrd", "Shui", "Sidd", "Sidt", "Sind", "Sinh", "Sogd", "Sogo", "Sora", "Soyo", "Sund", "Sunu", "Sylo", "Syrc", "Syre", "Syrj", "Syrn", "Tagb", "Takr", "Tale", "Talu", "Taml", "Tang", "Tavt", "Tayo", "Telu", "Teng", "Tfng", "Tglg", "Thaa", "Thai", "Tibt", "Tirh", "Tnsa", "Todr", "Tols", "Toto", "Tutg", "Ugar", "Vaii", "Visp", "Vith", "Wara", "Wcho", "Wole", "Xpeo", "Xsux", "Yezi", "Yiii", "Zanb", "Zinh", "Zmth", "Zsye", "Zsym", "Zxxx", "Zyyy", "Zzzz"] + fileprivate static let allScripts = [ + "Adlm", "Afak", "Aghb", "Ahom", "Arab", "Aran", "Armi", "Armn", "Avst", "Bali", "Bamu", + "Bass", "Batk", "Beng", "Berf", "Bhks", "Blis", "Bopo", "Brah", "Brai", "Bugi", "Buhd", + "Cakm", "Cans", "Cari", "Cham", "Cher", "Chis", "Chrs", "Cirt", "Copt", "Cpmn", "Cprt", + "Cyrl", "Cyrs", "Deva", "Diak", "Dogr", "Dsrt", "Dupl", "Egyd", "Egyh", "Egyp", "Elba", + "Elym", "Ethi", "Gara", "Geok", "Geor", "Glag", "Gong", "Gonm", "Goth", "Gran", "Grek", + "Gujr", "Gukh", "Guru", "Hanb", "Hang", "Hani", "Hano", "Hans", "Hant", "Hatr", "Hebr", + "Hira", "Hluw", "Hmng", "Hmnp", "Hntl", "Hrkt", "Hung", "Inds", "Ital", "Jamo", "Java", + "Jpan", "Jurc", "Kali", "Kana", "Kawi", "Khar", "Khmr", "Khoj", "Kitl", "Kits", "Knda", + "Kore", "Kpel", "Krai", "Kthi", "Lana", "Laoo", "Latf", "Latg", "Latn", "Leke", "Lepc", + "Limb", "Lina", "Linb", "Lisu", "Loma", "Lyci", "Lydi", "Mahj", "Maka", "Mand", "Mani", + "Marc", "Maya", "Medf", "Mend", "Merc", "Mero", "Mlym", "Modi", "Mong", "Moon", "Mroo", + "Mtei", "Mult", "Mymr", "Nagm", "Nand", "Narb", "Nbat", "Newa", "Nkdb", "Nkgb", "Nkoo", + "Nshu", "Ogam", "Olck", "Onao", "Orkh", "Orya", "Osge", "Osma", "Ougr", "Palm", "Pauc", + "Pcun", "Pelm", "Perm", "Phag", "Phli", "Phlp", "Phlv", "Phnx", "Piqd", "Plrd", "Prti", + "Psin", "Qaaa-Qabx", "Ranj", "Rjng", "Rohg", "Roro", "Runr", "Samr", "Sara", "Sarb", "Saur", + "Seal", "Sgnw", "Shaw", "Shrd", "Shui", "Sidd", "Sidt", "Sind", "Sinh", "Sogd", "Sogo", + "Sora", "Soyo", "Sund", "Sunu", "Sylo", "Syrc", "Syre", "Syrj", "Syrn", "Tagb", "Takr", + "Tale", "Talu", "Taml", "Tang", "Tavt", "Tayo", "Telu", "Teng", "Tfng", "Tglg", "Thaa", + "Thai", "Tibt", "Tirh", "Tnsa", "Todr", "Tols", "Toto", "Tutg", "Ugar", "Vaii", "Visp", + "Vith", "Wara", "Wcho", "Wole", "Xpeo", "Xsux", "Yezi", "Yiii", "Zanb", "Zinh", "Zmth", + "Zsye", "Zsym", "Zxxx", "Zyyy", "Zzzz", + ] fileprivate static let allAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" fileprivate static let allAlphaNum = allAlpha + "0123456789" fileprivate static let allRegionsTwoDigit = [ @@ -5583,7 +6585,6 @@ public class ProgramBuilder { } } - @discardableResult static func constructIntlScriptString() -> String { if probability(0.7) { @@ -5624,7 +6625,7 @@ public class ProgramBuilder { } } - @discardableResult + @discardableResult func constructIntlLocale() -> Variable { let intl = createNamedVariable(forBuiltin: "Intl") let constructor = getProperty("Locale", of: intl) @@ -5685,7 +6686,8 @@ public class ProgramBuilder { @discardableResult func constructIntlRelativeTimeFormat() -> Variable { - return constructIntlType(type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) + return constructIntlType( + type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) } @discardableResult @@ -5703,10 +6705,12 @@ public class ProgramBuilder { let types = fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues let type = types.randomElement()! let locale = loadString(ProgramBuilder.constructIntlLocaleString()) - let options = createOptionsBag(.jsIntlDisplayNamesSettings, + let options = createOptionsBag( + .jsIntlDisplayNamesSettings, predefined: ["type": loadString(type)]) construct(ctor, withArgs: [locale, options]) - let code = switch type { + let code = + switch type { case "language": ProgramBuilder.constructIntlLanguageString() case "region": @@ -5718,11 +6722,13 @@ public class ProgramBuilder { case "calendar": fuzzer.environment.getEnum(ofName: "temporalCalendar")!.enumValues.randomElement()! case "dateTimeField": - ["era", "year", "quarter", "month", "weekOfYear", "weekday", "day", - "dayPeriod", "hour", "minute", "second", "timeZoneName"].randomElement()! + [ + "era", "year", "quarter", "month", "weekOfYear", "weekday", "day", + "dayPeriod", "hour", "minute", "second", "timeZoneName", + ].randomElement()! default: String.random(ofLength: 4) - } + } return callMethod("of", on: ctor, withArgs: [loadString(code)]) } } diff --git a/Sources/Fuzzilli/Base/Timers.swift b/Sources/Fuzzilli/Base/Timers.swift index f1d3ed899..eda2a07f0 100644 --- a/Sources/Fuzzilli/Base/Timers.swift +++ b/Sources/Fuzzilli/Base/Timers.swift @@ -16,7 +16,7 @@ import Foundation let Seconds = 1.0 let Minutes = 60.0 * Seconds -let Hours = 60.0 * Minutes +let Hours = 60.0 * Minutes /// API to schedule tasks to run after a specified interval and possibly repeatedly on the DispatchQueue of the associated fuzzer instance. public class Timers { @@ -47,7 +47,9 @@ public class Timers { /// - interval: The interval (in seconds) between two executions of the task. /// - repetitions: The total number of executions of the task. /// - task: The task to execute. - public func scheduleTask(every interval: TimeInterval, repeat repetitions: Int, _ task: @escaping () -> Void) { + public func scheduleTask( + every interval: TimeInterval, repeat repetitions: Int, _ task: @escaping () -> Void + ) { guard repetitions > 0 else { return } diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 61d9e181e..e4d7dfc7f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -17,8 +17,8 @@ protocol GeneratorAdapter { func run(in b: ProgramBuilder, with inputs: [Variable]) } -public typealias GeneratorFuncNoArgs = (ProgramBuilder) -> () -fileprivate struct GeneratorAdapterNoArgs: GeneratorAdapter { +public typealias GeneratorFuncNoArgs = (ProgramBuilder) -> Void +private struct GeneratorAdapterNoArgs: GeneratorAdapter { let expectedNumberOfInputs = 0 let f: GeneratorFuncNoArgs func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -27,8 +27,8 @@ fileprivate struct GeneratorAdapterNoArgs: GeneratorAdapter { } } -public typealias GeneratorFunc1Arg = (ProgramBuilder, Variable) -> () -fileprivate struct GeneratorAdapter1Arg: GeneratorAdapter { +public typealias GeneratorFunc1Arg = (ProgramBuilder, Variable) -> Void +private struct GeneratorAdapter1Arg: GeneratorAdapter { let expectedNumberOfInputs = 1 let f: GeneratorFunc1Arg func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -37,8 +37,8 @@ fileprivate struct GeneratorAdapter1Arg: GeneratorAdapter { } } -public typealias GeneratorFunc2Args = (ProgramBuilder, Variable, Variable) -> () -fileprivate struct GeneratorAdapter2Args: GeneratorAdapter { +public typealias GeneratorFunc2Args = (ProgramBuilder, Variable, Variable) -> Void +private struct GeneratorAdapter2Args: GeneratorAdapter { let expectedNumberOfInputs = 2 let f: GeneratorFunc2Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -47,8 +47,8 @@ fileprivate struct GeneratorAdapter2Args: GeneratorAdapter { } } -public typealias GeneratorFunc3Args = (ProgramBuilder, Variable, Variable, Variable) -> () -fileprivate struct GeneratorAdapter3Args: GeneratorAdapter { +public typealias GeneratorFunc3Args = (ProgramBuilder, Variable, Variable, Variable) -> Void +private struct GeneratorAdapter3Args: GeneratorAdapter { let expectedNumberOfInputs = 3 let f: GeneratorFunc3Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -57,8 +57,9 @@ fileprivate struct GeneratorAdapter3Args: GeneratorAdapter { } } -public typealias GeneratorFunc4Args = (ProgramBuilder, Variable, Variable, Variable, Variable) -> () -fileprivate struct GeneratorAdapter4Args: GeneratorAdapter { +public typealias GeneratorFunc4Args = (ProgramBuilder, Variable, Variable, Variable, Variable) -> + Void +private struct GeneratorAdapter4Args: GeneratorAdapter { let expectedNumberOfInputs = 4 let f: GeneratorFunc4Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -82,10 +83,10 @@ public class GeneratorStub: Contributor { case None case IsWasmArray case IsWasmStruct - case IsWasmFunction // On a type definition this means "signature". + case IsWasmFunction // On a type definition this means "signature". } - public struct Constraint : Hashable { + public struct Constraint: Hashable { let type: ILType let additional: AdditionalConstraints @@ -99,32 +100,32 @@ public class GeneratorStub: Contributor { return false } return switch additional { - case .None: - true - case .IsWasmArray: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmArrayTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmArrayRef()) - } else { - false - } - case .IsWasmStruct: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmStructTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmStructRef()) - } else { - false - } - case .IsWasmFunction: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmSignatureTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmFuncRef()) - } else { - false - } + case .None: + true + case .IsWasmArray: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmArrayTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmArrayRef()) + } else { + false + } + case .IsWasmStruct: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmStructTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmStructRef()) + } else { + false + } + case .IsWasmFunction: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmSignatureTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmFuncRef()) + } else { + false + } } } @@ -195,20 +196,19 @@ public class GeneratorStub: Contributor { return Inputs(constraints: [jsAny, jsAny, jsAny, jsAny], mode: .loose) } - // A number of inputs that should have the specified type, but may also be of a wider, or even different, type. // This should usually be used instead of .required since it will ensure that also variables of unknown type can // be used as inputs during code generation. public static func preferred(_ types: ILType...) -> Inputs { assert(!types.isEmpty) - return Inputs(constraints: types.map {Constraint($0)}, mode: .loose) + return Inputs(constraints: types.map { Constraint($0) }, mode: .loose) } // A number of inputs that must have the specified type. // Only use this if the code generator cannot do anything meaningful if it receives a value of the wrong type. public static func required(_ types: ILType...) -> Inputs { assert(!types.isEmpty) - return Inputs(constraints: types.map {Constraint($0)}, mode: .strict) + return Inputs(constraints: types.map { Constraint($0) }, mode: .strict) } public static func requiredComplex(_ constraints: Constraint...) -> Inputs { @@ -231,7 +231,7 @@ public class GeneratorStub: Contributor { // E.g. .either([.javascript, .classDefinition]) which is basically either one of .javascript or .classDefinition case either([Context]) - var isSingle : Bool { + var isSingle: Bool { self.getSingle() != nil } @@ -241,25 +241,27 @@ public class GeneratorStub: Contributor { func getSingle() -> Context? { switch self { - case .single(let ctx): - return ctx - default: - return nil + case .single(let ctx): + return ctx + default: + return nil } } // Whether the ContextRequirement is satisified for the given (current) context. func satisfied(by context: Context) -> Bool { switch self { - case .single(let ctx): - return ctx.isSubset(of: context) - case .either(let ctxs): - // We do this check here since we cannot check on construction whether we have used .either correctly. - assert(ctxs.count > 1, "Something seems wrong, one should have more than a single context here") - // Any of the Contexts needs to be satisfied. - return ctxs.contains(where: { ctx in - ctx.isSubset(of: context) - }) + case .single(let ctx): + return ctx.isSubset(of: context) + case .either(let ctxs): + // We do this check here since we cannot check on construction whether we have used .either correctly. + assert( + ctxs.count > 1, + "Something seems wrong, one should have more than a single context here") + // Any of the Contexts needs to be satisfied. + return ctxs.contains(where: { ctx in + ctx.isSubset(of: context) + }) } } @@ -268,15 +270,17 @@ public class GeneratorStub: Contributor { // This is used in consistency checking in `ContextGraph` initialization where a previous generator might open multiple contexts. func matches(_ context: Context) -> Bool { switch self { - case .single(let ctx): - return ctx == context - case .either(let ctxs): - // We do this check here since we cannot check on construction whether we have used .either correctly. - assert(ctxs.count > 1, "Something seems wrong, one should have more than a single context here") - // All contexts need to be in the current context. - return ctxs.allSatisfy { ctx in - ctx.isSubset(of: context) - } + case .single(let ctx): + return ctx == context + case .either(let ctxs): + // We do this check here since we cannot check on construction whether we have used .either correctly. + assert( + ctxs.count > 1, + "Something seems wrong, one should have more than a single context here") + // All contexts need to be in the current context. + return ctxs.allSatisfy { ctx in + ctx.isSubset(of: context) + } } } } @@ -295,7 +299,10 @@ public class GeneratorStub: Contributor { /// Wrapper around the actual generator function called. private let adapter: GeneratorAdapter - fileprivate init(name: String, inputs: Inputs, produces: [Constraint] = [], context: ContextRequirement, providedContext: [Context] = [], adapter: GeneratorAdapter) { + fileprivate init( + name: String, inputs: Inputs, produces: [Constraint] = [], context: ContextRequirement, + providedContext: [Context] = [], adapter: GeneratorAdapter + ) { self.inputs = inputs self.produces = produces @@ -307,8 +314,13 @@ public class GeneratorStub: Contributor { assert(inputs.count == adapter.expectedNumberOfInputs) } - fileprivate convenience init(name: String, inputs: Inputs, produces: [ILType] = [], context: ContextRequirement, providedContext: [Context] = [], adapter: GeneratorAdapter) { - self.init(name: name, inputs: inputs, produces: produces.map {Constraint($0)}, context: context, providedContext: providedContext, adapter: adapter) + fileprivate convenience init( + name: String, inputs: Inputs, produces: [ILType] = [], context: ContextRequirement, + providedContext: [Context] = [], adapter: GeneratorAdapter + ) { + self.init( + name: name, inputs: inputs, produces: produces.map { Constraint($0) }, context: context, + providedContext: providedContext, adapter: adapter) } /// Execute this code generator, generating new code at the current position in the ProgramBuilder. @@ -323,32 +335,66 @@ public class GeneratorStub: Contributor { return addedInstructions } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name: name, inputs: .none, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), producesComplex: [Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + producesComplex: [Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name: name, inputs: .none, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc2Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc2Args + ) { assert(inputs.count == 2) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc3Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc3Args + ) { assert(inputs.count == 3) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc4Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc4Args + ) { assert(inputs.count == 4) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) } } @@ -359,7 +405,6 @@ public class CodeGenerator { // Here, I think we might have different Contexts that each yield point could provide, e.g. [.javascript | .subroutine, .wasmFunction]. Unsure if there is a situation where this matters? instead of having .javascript | .subroutine | .wasmFunction? public let providedContexts: [Context] - public init(_ name: String, _ generators: [GeneratorStub]) { self.parts = generators self.name = name @@ -378,7 +423,7 @@ public class CodeGenerator { // This essentially means that all stubs have no requirements. // Usually there is only a single element in the CodeGenerator if it is a ValueGenerator. public var isValueGenerator: Bool { - return self.parts.allSatisfy {$0.isValueStub} + return self.parts.allSatisfy { $0.isValueStub } } // This is the context required by the first part of the CodeGenerator. @@ -405,7 +450,7 @@ public class CodeGenerator { return self.parts[1...] } - public var expandedName : String { + public var expandedName: String { if self.name == "Synthetic" { return "Synthetic(\(self.parts.map{$0.name}.joined(separator: ",")))" } else { @@ -413,37 +458,106 @@ public class CodeGenerator { } } - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name, [GeneratorStub(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name, [GeneratorStub(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: .none, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], + _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: .none, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, producesComplex: [GeneratorStub.Constraint], + provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc2Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc2Args + ) { assert(inputs.count == 2) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter2Args(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc3Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc3Args + ) { assert(inputs.count == 3) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter3Args(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc4Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc4Args + ) { assert(inputs.count == 4) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter4Args(f: f))]) + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) + ]) } } diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index d8f8890fd..f759f51ff 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -16,9 +16,10 @@ import Foundation // Generator stubs for disposable and async-disposable object variables. func disposableObjVariableGeneratorStubs( - inContext contextRequirement : Context, - withSymbol symbolProperty : String, - genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { + inContext contextRequirement: Context, + withSymbol symbolProperty: String, + genDisposableVariable: @escaping (ProgramBuilder, Variable) -> Void +) -> [GeneratorStub] { return [ GeneratorStub( "DisposableObjectLiteralBeginGenerator", @@ -64,9 +65,10 @@ func disposableObjVariableGeneratorStubs( // Generator stubs for disposable and async-disposable class variables. func disposableClassVariableGeneratorStubs( - inContext contextRequirement : Context, - withSymbol symbolProperty : String, - genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { + inContext contextRequirement: Context, + withSymbol symbolProperty: String, + genDisposableVariable: @escaping (ProgramBuilder, Variable) -> Void +) -> [GeneratorStub] { return [ GeneratorStub( "DisposableClassDefinitionBeginGenerator", @@ -85,10 +87,12 @@ func disposableClassVariableGeneratorStubs( superclass = b.randomVariable(ofType: .constructor()) } let inputs = superclass != nil ? [superclass!] : [] - let cls = b.emit(BeginClassDefinition( + let cls = b.emit( + BeginClassDefinition( hasSuperclass: superclass != nil, isExpression: probability(0.3)), - withInputs: inputs).output + withInputs: inputs + ).output b.runtimeData.push("class", cls) }, GeneratorStub( @@ -164,7 +168,8 @@ public let CodeGenerators: [CodeGenerator] = [ b.loadString(b.randomString()) }, - CodeGenerator("ConcatenatedStringGenerator", inputs: .required(.string), produces: [.string]) { b, inputString in + CodeGenerator("ConcatenatedStringGenerator", inputs: .required(.string), produces: [.string]) { + b, inputString in // Emit a dynamically concatenated string, e.g. something like: // let select = someVar ? "string a" : "string b"; // let result = select + "other string"; @@ -227,20 +232,21 @@ public let CodeGenerators: [CodeGenerator] = [ var elements = [Variable]() // Randomly select the type of elements to surround the holes with. - let getElementOptions : [() -> Variable] = [ + let getElementOptions: [() -> Variable] = [ // Holey Smi (in most cases) - {b.randomVariable(ofType: .integer) ?? b.loadInt(b.randomInt())}, + { b.randomVariable(ofType: .integer) ?? b.loadInt(b.randomInt()) }, // Holey Double - {b.randomVariable(ofType: .float) ?? b.loadFloat(b.randomFloat())}, + { b.randomVariable(ofType: .float) ?? b.loadFloat(b.randomFloat()) }, // Holey Elements - {b.randomJsVariable()} + { b.randomJsVariable() }, ] let getElement = getElementOptions.randomElement()! - let guaranteeHole = Int.random(in: 0.. () + private let f: (ProgramBuilder) -> Void - public init(_ name: String, _ f: @escaping (_: ProgramBuilder) -> ()) { + public init(_ name: String, _ f: @escaping (_: ProgramBuilder) -> Void) { self.f = f super.init(name: name) } @@ -28,4 +28,3 @@ public class ProgramTemplate: Contributor { /// Strongly typed ProgramTemplate that can be used to differentiate templates that make use of Wasm. public class WasmProgramTemplate: ProgramTemplate { } - diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 9fce1cfd4..a1fc15184 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - /// Builtin program templates to target specific types of bugs. public let ProgramTemplates = [ ProgramTemplate("Codegen100") { b in @@ -29,7 +28,7 @@ public let ProgramTemplates = [ WasmProgramTemplate("WasmCodegen50") { b in b.buildPrefix() - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 50) } b.build(n: 10) @@ -41,7 +40,7 @@ public let ProgramTemplates = [ WasmProgramTemplate("WasmCodegen100") { b in b.buildPrefix() - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 100) } b.build(n: 10) @@ -54,8 +53,8 @@ public let ProgramTemplates = [ WasmProgramTemplate("MixedJsAndWasm1") { b in b.buildPrefix() b.build(n: 10) - let m = b.buildWasmModule() { _ in - b.build(n:30) + let m = b.buildWasmModule { _ in + b.build(n: 30) } b.build(n: 20) @@ -67,11 +66,11 @@ public let ProgramTemplates = [ WasmProgramTemplate("MixedJsAndWasm2") { b in b.buildPrefix() b.build(n: 10) - b.buildWasmModule() { _ in + b.buildWasmModule { _ in b.build(n: 20) } b.build(n: 10) - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 20) } b.build(n: 20) @@ -87,25 +86,31 @@ public let ProgramTemplates = [ var f: Variable? = nil - withEqualProbability({ - f = b.buildAsyncFunction(with: b.randomParameters()) { _ in - b.build(n: Int.random(in: 5...20)) - } - }, { - f = b.buildPlainFunction(with: b.randomParameters()) { _ in - b.build(n: Int.random(in: 5...20)) - } - }) + withEqualProbability( + { + f = b.buildAsyncFunction(with: b.randomParameters()) { _ in + b.build(n: Int.random(in: 5...20)) + } + }, + { + f = b.buildPlainFunction(with: b.randomParameters()) { _ in + b.build(n: Int.random(in: 5...20)) + } + }) let signature = b.type(of: f!).signature ?? Signature.forUnknownFunction // As we do not yet know what types we have in the Wasm module when we try to call this, let Fuzzilli know that it could potentially use all Wasm types here. - let allWasmTypes: WeightedList = WeightedList([(.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), (.wasmFuncRef(), 1)]) + let allWasmTypes: WeightedList = WeightedList([ + (.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), + (.wasmFuncRef(), 1), + ]) - var wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(signature, availableTypes: allWasmTypes) + var wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + signature, availableTypes: allWasmTypes) let wrapped = b.wrapSuspending(function: f!) let m = b.buildWasmModule { mod in - mod.addWasmFunction(with: [] => []) { fbuilder, _, _ in + mod.addWasmFunction(with: [] => []) { fbuilder, _, _ in // This will create a bunch of locals, which should create large (>4KB) frames. if probability(0.02) { for _ in 0..<1000 { @@ -117,7 +122,8 @@ public let ProgramTemplates = [ // Best effort call... // TODO: Extend findOrGenerateArguments to work in Wasm as well. if let args { - fbuilder.wasmJsCall(function: wrapped, withArgs: args, withWasmSignature: wasmSignature) + fbuilder.wasmJsCall( + function: wrapped, withArgs: args, withWasmSignature: wasmSignature) } b.build(n: 4) return [] @@ -135,7 +141,8 @@ public let ProgramTemplates = [ b.build(n: 10) - b.callFunction(exportedMethod, withArgs: b.randomArguments(forCallingFunctionWithSignature: signature)) + b.callFunction( + exportedMethod, withArgs: b.randomArguments(forCallingFunctionWithSignature: signature)) b.build(n: 5) }, @@ -152,22 +159,29 @@ public let ProgramTemplates = [ let tagToThrow = chooseUniform(from: wasmTags) let throwParamTypes = b.type(of: tagToThrow).wasmTagType!.parameters let tagToCatchForRethrow = chooseUniform(from: tags) - let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef()] + let catchBlockOutputTypes = + b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef()] let module = b.buildWasmModule { wasmModule in // Wasm function that throws a tag, catches a tag (the same or a different one) to // rethrow it again (or another exnref if present). wasmModule.addWasmFunction(with: [] => []) { function, label, args in b.build(n: 10) - let caughtValues = function.wasmBuildBlockWithResults(with: [] => catchBlockOutputTypes, args: []) { catchRefLabel, _ in + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => catchBlockOutputTypes, args: [] + ) { catchRefLabel, _ in // TODO(mliedtke): We should probably allow mutations of try_tables to make // these cases more generic. This would probably require being able to wrap // things in a new block (so we can insert a target destination for a new catch // with a matching signature) or to at least create a new tag for an existing // block target. Either way, this is non-trivial. - function.wasmBuildTryTable(with: [] => [], args: [tagToCatchForRethrow, catchRefLabel], catches: [.Ref]) { _, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagToCatchForRethrow, catchRefLabel], catches: [.Ref] + ) { _, _ in b.build(n: 10) - function.WasmBuildThrow(tag: tagToThrow, inputs: throwParamTypes.map(function.findOrGenerateWasmVar)) + function.WasmBuildThrow( + tag: tagToThrow, + inputs: throwParamTypes.map(function.findOrGenerateWasmVar)) return [] } return catchBlockOutputTypes.map(function.findOrGenerateWasmVar) @@ -201,29 +215,37 @@ public let ProgramTemplates = [ let numCallees = Int.random(in: 1...5) let module = b.buildWasmModule { wasmModule in - let callees = (0.. 10) - return Int.random(in: (numIterations - 10).. 10) + return Int.random(in: (numIterations - 10).. [.wasmi32]) { f, _, args in // Interleave random Wasm instructions before growing b.build(n: 15) @@ -597,23 +637,33 @@ public let ProgramTemplates = [ // B. Create View (that will likely detach soon) let buffer = b.getProperty("buffer", of: memory) - let TypedArray = b.createNamedVariable(forBuiltin: chooseUniform(from: ["Int8Array", "Uint32Array", "Float64Array", "DataView"])) + let TypedArray = b.createNamedVariable( + forBuiltin: chooseUniform(from: [ + "Int8Array", "Uint32Array", "Float64Array", "DataView", + ])) let view = b.construct(TypedArray, withArgs: [buffer]) b.build(n: 3) // C. Growth/Resize Event (Mix of JS, Wasm, and RAB APIs) - withEqualProbability({ - _ = b.callMethod("grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...4))], guard: true) - }, { - _ = b.callFunction(wasmGrow, withArgs: [b.loadInt(Int64.random(in: 0...4))]) - }, { - let isResizable = b.getProperty("resizable", of: buffer) - b.buildIf(isResizable) { - let currentLen = b.getProperty("byteLength", of: buffer) - let newLen = b.binary(currentLen, b.loadInt(Int64(WasmConstants.specWasmMemPageSize)), with: .Add) - b.callMethod("resize", on: buffer, withArgs: [newLen]) - } - }) + withEqualProbability( + { + _ = b.callMethod( + "grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...4))], + guard: true) + }, + { + _ = b.callFunction(wasmGrow, withArgs: [b.loadInt(Int64.random(in: 0...4))]) + }, + { + let isResizable = b.getProperty("resizable", of: buffer) + b.buildIf(isResizable) { + let currentLen = b.getProperty("byteLength", of: buffer) + let newLen = b.binary( + currentLen, b.loadInt(Int64(WasmConstants.specWasmMemPageSize)), + with: .Add) + b.callMethod("resize", on: buffer, withArgs: [newLen]) + } + }) } b.build(n: 15) } diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index b6050f5ea..eb5c1c514 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -27,7 +27,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), produces: [.object(ofGroup: "WasmGlobal")] ) { b in - b.createWasmGlobal(value: b.randomWasmGlobal(forContext: .javascript), isMutable: probability(0.5)) + b.createWasmGlobal( + value: b.randomWasmGlobal(forContext: .javascript), isMutable: probability(0.5)) }, CodeGenerator( @@ -77,55 +78,62 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ]), - CodeGenerator("WasmTypeGroupGenerator", [ - GeneratorStub( - "WasmTypeGroupBeginGenerator", - provides: [.wasmTypeGroup] - ) { b in - b.emit(WasmBeginTypeGroup()) - }, - GeneratorStub( - "WasmTypeGroupEndGenerator", - inContext: .single(.wasmTypeGroup) - ) { b in - b.wasmEndTypeGroup() - }, - ]), - - CodeGenerator("WasmTypeGroupWithAllTypesGenerator", [ - GeneratorStub( - "WasmTypeGroupBeginGenerator", - provides: [.wasmTypeGroup] - ) { b in - b.emit(WasmBeginTypeGroup()) - }, - wasmArrayTypeGenerator, - wasmStructTypeGenerator, - wasmSignatureTypeGenerator, - GeneratorStub( - "WasmTypeGroupEndGenerator", - inContext: .single(.wasmTypeGroup), - producesComplex: [ - .init(.wasmTypeDef(), .IsWasmArray), - .init(.wasmTypeDef(), .IsWasmStruct), - .init(.wasmTypeDef(), .IsWasmFunction) - ] - ) { b in - b.wasmEndTypeGroup() - }, - ]), + CodeGenerator( + "WasmTypeGroupGenerator", + [ + GeneratorStub( + "WasmTypeGroupBeginGenerator", + provides: [.wasmTypeGroup] + ) { b in + b.emit(WasmBeginTypeGroup()) + }, + GeneratorStub( + "WasmTypeGroupEndGenerator", + inContext: .single(.wasmTypeGroup) + ) { b in + b.wasmEndTypeGroup() + }, + ]), + + CodeGenerator( + "WasmTypeGroupWithAllTypesGenerator", + [ + GeneratorStub( + "WasmTypeGroupBeginGenerator", + provides: [.wasmTypeGroup] + ) { b in + b.emit(WasmBeginTypeGroup()) + }, + wasmArrayTypeGenerator, + wasmStructTypeGenerator, + wasmSignatureTypeGenerator, + GeneratorStub( + "WasmTypeGroupEndGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [ + .init(.wasmTypeDef(), .IsWasmArray), + .init(.wasmTypeDef(), .IsWasmStruct), + .init(.wasmTypeDef(), .IsWasmFunction), + ] + ) { b in + b.wasmEndTypeGroup() + }, + ]), CodeGenerator("WasmArrayTypeGenerator", [wasmArrayTypeGenerator]), CodeGenerator("WasmStructTypeGenerator", [wasmStructTypeGenerator]), CodeGenerator("WasmSignatureTypeGenerator", [wasmSignatureTypeGenerator]), - CodeGenerator("WasmSelfReferenceGenerator", inContext: .single(.wasmTypeGroup), produces: [.wasmSelfReference()]) { b in + CodeGenerator( + "WasmSelfReferenceGenerator", inContext: .single(.wasmTypeGroup), + produces: [.wasmSelfReference()] + ) { b in b.wasmDefineForwardOrSelfReference() }, CodeGenerator("WasmForwardReferenceGenerator", inContext: .single(.wasmTypeGroup)) { b in // TODO(cffsmith): think about this. - b.wasmDefineAndResolveForwardReference {b.buildRecursive(n: defaultCodeGenerationAmount)} + b.wasmDefineAndResolveForwardReference { b.buildRecursive(n: defaultCodeGenerationAmount) } }, CodeGenerator( @@ -138,10 +146,13 @@ public let WasmCodeGenerators: [CodeGenerator] = [ as? WasmArrayTypeDescription { let function = b.currentWasmModule.currentWasmFunction - let hasElement = b.findVariable{b.type(of: $0).Is(typeDesc.elementType.unpacked())} != nil + let hasElement = + b.findVariable { b.type(of: $0).Is(typeDesc.elementType.unpacked()) } != nil let isDefaultable = typeDesc.elementType.isWasmDefaultable - if hasElement && (!isDefaultable || probability(0.5)) { - let elements = (0.. outputTypes) b.runtimeData.push("blockSignature", signature) - b.emit(WasmBeginBlock(parameterCount: parameters.count), withInputs: [signature] + args) + b.emit( + WasmBeginBlock(parameterCount: parameters.count), withInputs: [signature] + args + ) }, GeneratorStub("WasmEndBlockGenerator", inContext: .single(.wasmFunction)) { b in let signature = b.runtimeData.pop("blockSignature") @@ -1397,7 +1503,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.emit(WasmBeginLoop(with: [] => []), withInputs: [signature]) // Increase loop counter. let result = function.wasmi32BinOp( - loopCtr, function.consti32(1), binOpKind: .Sub) + loopCtr, function.consti32(1), binOpKind: .Sub) function.wasmReassign(variable: loopCtr, to: result) }, GeneratorStub( @@ -1408,53 +1514,63 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let loopCtr = b.runtimeData.pop("loopCounter") // Backedge of loop, we continue if it is not equal to zero. let isNotZero = function.wasmi32CompareOp(loopCtr, function.consti32(0), using: .Ne) - b.emit(WasmEndLoop(outputCount: 0), withInputs: [b.runtimeData.pop("loopSignature")]) + b.emit( + WasmEndLoop(outputCount: 0), withInputs: [b.runtimeData.pop("loopSignature")]) }, ]), - CodeGenerator("WasmLoopWithSignatureGenerator", [ - GeneratorStub("WasmBeginLoopWithSignatureGenerator", inContext: .single(.wasmFunction), - provides: [.wasmFunction]) { b in - let function = b.currentWasmModule.currentWasmFunction - // Count upwards here to make it slightly more different from the other loop generator. - // Also, instead of using reassign, this generator uses the signature to pass and update the loop counter. - let randomArgs = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) - let randomArgTypes = randomArgs.map { b.type(of: $0) } - let args = [function.consti32(0)] + randomArgs - let parameters = args.map(b.type) - // TODO(mliedtke): Also allow index types in the output types. - let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) - let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) - let loopBegin = b.emit(WasmBeginLoop(parameterCount: parameters.count), - withInputs: [signature] + args) - let loopCounter = loopBegin.innerOutput(1) - assert(b.type(of: loopCounter).Is(.wasmi32)) - b.runtimeData.push("loopCounter", loopCounter) - b.runtimeData.push("loopSignature", signature) - b.runtimeData.push("loopLabel", loopBegin.innerOutput(0)) - }, - GeneratorStub("WasmEndLoopWithSignatureGenerator", inContext: .single(.wasmFunction), - provides: [.wasmFunction]) { b in - let signature = b.runtimeData.pop("loopSignature") - let function = b.currentWasmModule.currentWasmFunction + CodeGenerator( + "WasmLoopWithSignatureGenerator", + [ + GeneratorStub( + "WasmBeginLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction] + ) { b in + let function = b.currentWasmModule.currentWasmFunction + // Count upwards here to make it slightly more different from the other loop generator. + // Also, instead of using reassign, this generator uses the signature to pass and update the loop counter. + let randomArgs = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) + let randomArgTypes = randomArgs.map { b.type(of: $0) } + let args = [function.consti32(0)] + randomArgs + let parameters = args.map(b.type) + // TODO(mliedtke): Also allow index types in the output types. + let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) + let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) + let loopBegin = b.emit( + WasmBeginLoop(parameterCount: parameters.count), + withInputs: [signature] + args) + let loopCounter = loopBegin.innerOutput(1) + assert(b.type(of: loopCounter).Is(.wasmi32)) + b.runtimeData.push("loopCounter", loopCounter) + b.runtimeData.push("loopSignature", signature) + b.runtimeData.push("loopLabel", loopBegin.innerOutput(0)) + }, + GeneratorStub( + "WasmEndLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction] + ) { b in + let signature = b.runtimeData.pop("loopSignature") + let function = b.currentWasmModule.currentWasmFunction - // Note that due to the do-while style implementation, the actual iteration count is at - // least 1. - let iterationCount = Int32.random(in: 0...16) - let loopCtr = function.wasmi32BinOp( - b.runtimeData.pop("loopCounter"), function.consti32(1), binOpKind: .Add) - let condition = function.wasmi32CompareOp( - loopCtr, function.consti32(iterationCount), using: .Lt_s) - let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature - let backedgeArgs = [loopCtr] + wasmSignature.parameterTypes.dropFirst() - .map {b.randomVariable(ofType: $0)!} - function.wasmBranchIf( - condition, to: b.runtimeData.pop("loopLabel"), args: backedgeArgs, - hint: b.randomWasmBranchHint()) - let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndLoop(outputCount: outputs.count), withInputs: [signature] + outputs) - }, - ]), + // Note that due to the do-while style implementation, the actual iteration count is at + // least 1. + let iterationCount = Int32.random(in: 0...16) + let loopCtr = function.wasmi32BinOp( + b.runtimeData.pop("loopCounter"), function.consti32(1), binOpKind: .Add) + let condition = function.wasmi32CompareOp( + loopCtr, function.consti32(iterationCount), using: .Lt_s) + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature + let backedgeArgs = + [loopCtr] + + wasmSignature.parameterTypes.dropFirst() + .map { b.randomVariable(ofType: $0)! } + function.wasmBranchIf( + condition, to: b.runtimeData.pop("loopLabel"), args: backedgeArgs, + hint: b.randomWasmBranchHint()) + let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) + b.emit(WasmEndLoop(outputCount: outputs.count), withInputs: [signature] + outputs) + }, + ]), // TODO split this into a multi-part Generator. CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { b in @@ -1566,8 +1682,10 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let signature = b.runtimeData.peek("ifSignature") let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature let trueResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmBeginElse(parameterCount: wasmSignature.parameterTypes.count, - outputCount: wasmSignature.outputTypes.count), + b.emit( + WasmBeginElse( + parameterCount: wasmSignature.parameterTypes.count, + outputCount: wasmSignature.outputTypes.count), withInputs: [signature] + trueResults) }, GeneratorStub( @@ -1578,7 +1696,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let signature = b.runtimeData.pop("ifSignature") let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature let falseResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndIf(outputCount: wasmSignature.outputTypes.count), + b.emit( + WasmEndIf(outputCount: wasmSignature.outputTypes.count), withInputs: [signature] + falseResults) }, ]), @@ -1634,9 +1753,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [ } // Create a try-catch throwing and catching a tag producing an exnref as // a result. - function.wasmBuildBlockWithResults(with: [] => (tagType.parameters + [.wasmExnRef()]), args: []) { label, _ in + function.wasmBuildBlockWithResults( + with: [] => (tagType.parameters + [.wasmExnRef()]), args: [] + ) { label, _ in let args = tagType.parameters.map(function.findOrGenerateWasmVar) - function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { _, _ in + function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { + _, _ in function.WasmBuildThrow(tag: tag, inputs: args) return [] } @@ -1724,7 +1846,9 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBranchTable(on: value, labels: labels, args: args) (0.. WasmBeginTryTable.CatchKind in @@ -1793,8 +1922,9 @@ public let WasmCodeGenerators: [CodeGenerator] = [ signatureDefs.reversed().enumerated().forEach { n, signatureDef in let wasmSignature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature let results = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndBlock(outputCount: wasmSignature.outputTypes.count), - withInputs: [signatureDef] + results) + b.emit( + WasmEndBlock(outputCount: wasmSignature.outputTypes.count), + withInputs: [signatureDef] + results) b.buildRecursive(n: defaultCodeGenerationAmount) } } @@ -1843,13 +1973,17 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmSimd128IntegerBinOp(lhs, rhs, shape, binOpKind) }, - CodeGenerator("WasmSimd128IntegerTernaryOpGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128)) { b, left, mid, right in - let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter{ !$0.isFloat() } ) - let ternaryOpKind = chooseUniform(from: WasmSimd128IntegerTernaryOpKind.allCases.filter{ - $0.isValidForShape(shape: shape) - }) + CodeGenerator( + "WasmSimd128IntegerTernaryOpGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128) + ) { b, left, mid, right in + let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter { !$0.isFloat() }) + let ternaryOpKind = chooseUniform( + from: WasmSimd128IntegerTernaryOpKind.allCases.filter { + $0.isValidForShape(shape: shape) + }) - let function = b.currentWasmModule.currentWasmFunction; + let function = b.currentWasmModule.currentWasmFunction function.wasmSimd128IntegerTernaryOp(left, mid, right, shape, ternaryOpKind) }, @@ -1883,13 +2017,17 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmSimd128FloatBinOp(lhs, rhs, shape, binOpKind) }, - CodeGenerator("WasmSimd128FloatTernaryOpGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128)) { b, left, mid, right in - let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter{ $0.isFloat() } ) - let ternaryOpKind = chooseUniform(from: WasmSimd128FloatTernaryOpKind.allCases.filter{ - $0.isValidForShape(shape: shape) - }) + CodeGenerator( + "WasmSimd128FloatTernaryOpGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128) + ) { b, left, mid, right in + let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter { $0.isFloat() }) + let ternaryOpKind = chooseUniform( + from: WasmSimd128FloatTernaryOpKind.allCases.filter { + $0.isValidForShape(shape: shape) + }) - let function = b.currentWasmModule.currentWasmFunction; + let function = b.currentWasmModule.currentWasmFunction function.wasmSimd128FloatTernaryOp(left, mid, right, shape, ternaryOpKind) }, @@ -2014,7 +2152,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ] -fileprivate let wasmArrayTypeGenerator = GeneratorStub( +private let wasmArrayTypeGenerator = GeneratorStub( "WasmArrayTypeGenerator", inContext: .single(.wasmTypeGroup), producesComplex: [.init(.wasmTypeDef(), .IsWasmArray)] @@ -2032,49 +2170,56 @@ fileprivate let wasmArrayTypeGenerator = GeneratorStub( mutability: mutability, indexType: elementType) } else { b.wasmDefineArrayType( - elementType: chooseUniform(from: [ - .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, - ] + WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: Bool.random())}), + elementType: chooseUniform( + from: [ + .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, + .wasmSimd128, + ] + + WasmAbstractHeapType.allCases.map { + ILType.wasmRef($0, nullability: Bool.random()) + }), mutability: mutability) } } -fileprivate let wasmStructTypeGenerator = GeneratorStub( +private let wasmStructTypeGenerator = GeneratorStub( "WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), - producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)]) { b in + producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)] +) { b in let (fields, indexTypes) = b.generateRandomWasmStructFields() b.wasmDefineStructType(fields: fields, indexTypes: indexTypes) } -fileprivate let wasmSignatureTypeGenerator = GeneratorStub( - "WasmSignatureTypeGenerator", - inContext: .single(.wasmTypeGroup), - producesComplex: [.init(.wasmTypeDef(), .IsWasmFunction)] - ) { b in - let typeCount = Int.random(in: 0...10) - let returnCount = Int.random(in: 0...typeCount) - let parameterCount = typeCount - returnCount - - var indexTypes: [Variable] = [] - let chooseType = { - var type: ILType - if let elementType = b.randomVariable(ofType: .wasmTypeDef()), - probability(0.25) - { - let nullability = - b.type(of: elementType).wasmTypeDefinition!.description - == .selfReference || probability(0.5) - indexTypes.append(elementType) - return ILType.wasmRef(.Index(), nullability: nullability) - } else { - // TODO(mliedtke): Extend list with abstract heap types. - return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128]) - } +private let wasmSignatureTypeGenerator = GeneratorStub( + "WasmSignatureTypeGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [.init(.wasmTypeDef(), .IsWasmFunction)] +) { b in + let typeCount = Int.random(in: 0...10) + let returnCount = Int.random(in: 0...typeCount) + let parameterCount = typeCount - returnCount + + var indexTypes: [Variable] = [] + let chooseType = { + var type: ILType + if let elementType = b.randomVariable(ofType: .wasmTypeDef()), + probability(0.25) + { + let nullability = + b.type(of: elementType).wasmTypeDefinition!.description + == .selfReference || probability(0.5) + indexTypes.append(elementType) + return ILType.wasmRef(.Index(), nullability: nullability) + } else { + // TODO(mliedtke): Extend list with abstract heap types. + return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128]) } - let signature = (0.. (0.. (0.. Variable { + private func compileClass( + _ name: String, superClass: ExpressionNode?, fields: [ClassFieldNode], isExpression: Bool + ) throws -> Variable { // The expressions for property values and computed properties need to be emitted before the class declaration is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() @@ -106,7 +108,9 @@ public class JavaScriptCompiler { let classDecl: Instruction if let superClass = superClass { let superClass = try compileExpression(superClass) - classDecl = emit(BeginClassDefinition(hasSuperclass: true, isExpression: isExpression), withInputs: [superClass]) + classDecl = emit( + BeginClassDefinition(hasSuperclass: true, isExpression: isExpression), + withInputs: [superClass]) } else { classDecl = emit(BeginClassDefinition(hasSuperclass: false, isExpression: isExpression)) } @@ -125,12 +129,16 @@ public class JavaScriptCompiler { var inputs = [Variable]() switch key { case .name(let name): - op = ClassAddProperty(propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddProperty( + propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic + ) case .index(let index): - op = ClassAddElement(index: index, hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddElement( + index: index, hasValue: property.hasValue, isStatic: property.isStatic) case .expression: inputs.append(computedKeys.removeLast()) - op = ClassAddComputedProperty(hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddComputedProperty( + hasValue: property.hasValue, isStatic: property.isStatic) } if property.hasValue { inputs.append(propertyValues.removeLast()) @@ -161,11 +169,18 @@ public class JavaScriptCompiler { } switch key { case .name(let name): - head = emit(BeginClassMethod(methodName: name, parameters: parameters, isStatic: method.isStatic)) + head = emit( + BeginClassMethod( + methodName: name, parameters: parameters, isStatic: method.isStatic)) case .index(let index): - head = emit(BeginClassMethod(methodName: String(index), parameters: parameters, isStatic: method.isStatic)) + head = emit( + BeginClassMethod( + methodName: String(index), parameters: parameters, + isStatic: method.isStatic)) case .expression: - head = emit(BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -195,9 +210,12 @@ public class JavaScriptCompiler { case .name(let name): head = emit(BeginClassGetter(propertyName: name, isStatic: getter.isStatic)) case .index(let index): - head = emit(BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) + head = emit( + BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) case .expression: - head = emit(BeginClassComputedGetter(isStatic: getter.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedGetter(isStatic: getter.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -223,9 +241,12 @@ public class JavaScriptCompiler { case .name(let name): head = emit(BeginClassSetter(propertyName: name, isStatic: setter.isStatic)) case .index(let index): - head = emit(BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) + head = emit( + BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) case .expression: - head = emit(BeginClassComputedSetter(isStatic: setter.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedSetter(isStatic: setter.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -264,7 +285,9 @@ public class JavaScriptCompiler { return classDecl.output } - private func compileInitialDeclarationValue(_ decl: Compiler_Protobuf_VariableDeclarator) throws -> Variable { + private func compileInitialDeclarationValue(_ decl: Compiler_Protobuf_VariableDeclarator) throws + -> Variable + { if decl.hasValue { return try compileExpression(decl.value) } else { @@ -305,10 +328,14 @@ public class JavaScriptCompiler { case .const: declarationMode = .const case .UNRECOGNIZED(let type): - throw CompilerError.invalidNodeError("invalid variable declaration type \(type)") + throw CompilerError.invalidNodeError( + "invalid variable declaration type \(type)") } - let v = emit(CreateNamedVariable(decl.name, declarationMode: declarationMode), withInputs: [initialValue]).output + let v = emit( + CreateNamedVariable(decl.name, declarationMode: declarationMode), + withInputs: [initialValue] + ).output // Variables declared with .var are allowed to overwrite each other. assert(!currentScope.keys.contains(decl.name) || declarationMode == .var) mapOrRemap(decl.name, to: v) @@ -318,14 +345,21 @@ public class JavaScriptCompiler { for decl in variableDeclaration.declarations { let initialValue = try compileInitialDeclarationValue(decl) - let v: Variable; + let v: Variable switch variableDeclaration.kind { case .using: - v = emit(CreateNamedDisposableVariable(decl.name), withInputs: [initialValue]).output + v = + emit(CreateNamedDisposableVariable(decl.name), withInputs: [initialValue]) + .output case .awaitUsing: - v = emit(CreateNamedAsyncDisposableVariable(decl.name), withInputs: [initialValue]).output + v = + emit( + CreateNamedAsyncDisposableVariable(decl.name), + withInputs: [initialValue] + ).output case .UNRECOGNIZED(let type): - throw CompilerError.invalidNodeError("invalid disposable variable declaration type \(type)") + throw CompilerError.invalidNodeError( + "invalid disposable variable declaration type \(type)") } assert(!currentScope.keys.contains(decl.name)) mapOrRemap(decl.name, to: v) @@ -333,19 +367,24 @@ public class JavaScriptCompiler { case .functionDeclaration(let functionDeclaration): let parameters = convertParameters(functionDeclaration.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation switch functionDeclaration.type { case .plain: - functionBegin = BeginPlainFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginPlainFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndPlainFunction() case .generator: - functionBegin = BeginGeneratorFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginGeneratorFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndGeneratorFunction() case .async: - functionBegin = BeginAsyncFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginAsyncFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndAsyncFunction() case .asyncGenerator: - functionBegin = BeginAsyncGeneratorFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginAsyncGeneratorFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndAsyncGeneratorFunction() case .UNRECOGNIZED(let type): throw CompilerError.invalidNodeError("invalid function declaration type \(type)") @@ -365,7 +404,9 @@ public class JavaScriptCompiler { case .classDeclaration(let classDeclaration): let superClass = classDeclaration.hasSuperClass ? classDeclaration.superClass : nil - try compileClass(classDeclaration.name, superClass: superClass, fields: classDeclaration.fields, isExpression: false) + try compileClass( + classDeclaration.name, superClass: superClass, fields: classDeclaration.fields, + isExpression: false) case .returnStatement(let returnStatement): if returnStatement.hasArgument { @@ -435,7 +476,8 @@ public class JavaScriptCompiler { case .declaration(let declaration): for declarator in declaration.declarations { loopVariables.append(declarator.name) - initialLoopVariableValues.append(try compileExpression(declarator.value)) + initialLoopVariableValues.append( + try compileExpression(declarator.value)) } case .expression(let expression): try compileExpression(expression) @@ -444,10 +486,13 @@ public class JavaScriptCompiler { } // Process condition. - var outputs = emit(BeginForLoopCondition(numLoopVariables: loopVariables.count), withInputs: initialLoopVariableValues).innerOutputs + var outputs = emit( + BeginForLoopCondition(numLoopVariables: loopVariables.count), + withInputs: initialLoopVariableValues + ).innerOutputs var cond: Variable? = nil try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) if forLoop.hasCondition { cond = try compileExpression(forLoop.condition) } else { @@ -456,9 +501,13 @@ public class JavaScriptCompiler { } // Process afterthought. - outputs = emit(BeginForLoopAfterthought(numLoopVariables: loopVariables.count), withInputs: [cond!]).innerOutputs + outputs = + emit( + BeginForLoopAfterthought(numLoopVariables: loopVariables.count), + withInputs: [cond!] + ).innerOutputs try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) if forLoop.hasAfterthought { try compileExpression(forLoop.afterthought) } @@ -467,16 +516,17 @@ public class JavaScriptCompiler { // Process body outputs = emit(BeginForLoopBody(numLoopVariables: loopVariables.count)).innerOutputs try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) try compileBody(forLoop.body) } emit(EndForLoop()) case .forInLoop(let forInLoop): - let initializer = forInLoop.left; + let initializer = forInLoop.left guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") + throw CompilerError.invalidNodeError( + "Expected no initial value for the variable declared in a for-in loop") } let obj = try compileExpression(forInLoop.right) @@ -490,9 +540,10 @@ public class JavaScriptCompiler { emit(EndForInLoop()) case .forOfLoop(let forOfLoop): - let initializer = forOfLoop.left; + let initializer = forOfLoop.left guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") + throw CompilerError.invalidNodeError( + "Expected no initial value for the variable declared in a for-of loop") } let obj = try compileExpression(forOfLoop.right) @@ -508,7 +559,7 @@ public class JavaScriptCompiler { case .breakStatement: // If we're in both .loop and .switch context, then the loop must be the most recent context // (switch blocks don't propagate an outer .loop context) so we just need to check for .loop here - if contextAnalyzer.context.contains(.loop){ + if contextAnalyzer.context.contains(.loop) { emit(LoopBreak()) } else if contextAnalyzer.context.contains(.switchCase) { emit(SwitchBreak()) @@ -615,7 +666,9 @@ public class JavaScriptCompiler { case .classExpression(let classExpression): let superClass = classExpression.hasSuperClass ? classExpression.superClass : nil - return try compileClass(classExpression.name, superClass: superClass, fields: classExpression.fields, isExpression: true) + return try compileClass( + classExpression.name, superClass: superClass, fields: classExpression.fields, + isExpression: true) case .ternaryExpression(let ternaryExpression): let condition = try compileExpression(ternaryExpression.condition) @@ -647,7 +700,7 @@ public class JavaScriptCompiler { } // Case 2 - assert(identifier.name != "this") // This is handled via ThisExpression + assert(identifier.name != "this") // This is handled via ThisExpression if identifier.name == "undefined" { return emit(LoadUndefined()).output } else if identifier.name == "arguments" { @@ -675,7 +728,10 @@ public class JavaScriptCompiler { // TODO should LoadBigInt support larger integer values (represented as string)? let stringValue = emit(LoadString(value: literal.value)).output let BigInt = emit(CreateNamedVariable("BigInt", declarationMode: .none)).output - return emit(CallFunction(numArguments: 1, isGuarded: false), withInputs: [BigInt, stringValue]).output + return emit( + CallFunction(numArguments: 1, isGuarded: false), + withInputs: [BigInt, stringValue] + ).output } case .stringLiteral(let literal): @@ -684,7 +740,8 @@ public class JavaScriptCompiler { case .templateLiteral(let templateLiteral): let interpolatedValues = try templateLiteral.expressions.map(compileExpression) - let parts = templateLiteral.parts.map({ $0.replacingOccurrences(of: "\n", with: "\\n") }) + let parts = templateLiteral.parts.map({ $0.replacingOccurrences(of: "\n", with: "\\n") } + ) return emit(CreateTemplateString(parts: parts), withInputs: interpolatedValues).output case .regExpLiteral(let literal): @@ -721,7 +778,8 @@ public class JavaScriptCompiler { // It's something like "+=", "-=", etc. let binaryOperator = String(assignmentExpression.operator.dropLast()) guard let op = BinaryOperator(rawValue: binaryOperator) else { - throw CompilerError.invalidNodeError("Unknown assignment operator \(assignmentExpression.operator)") + throw CompilerError.invalidNodeError( + "Unknown assignment operator \(assignmentExpression.operator)") } assignmentOperator = op } @@ -730,25 +788,37 @@ public class JavaScriptCompiler { case .memberExpression(let memberExpression): // Compile to a Set- or Update{Property/Element/ComputedProperty} operation let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError("missing property in member expression") + } switch property { case .name(let name): if let op = assignmentOperator { - emit(UpdateProperty(propertyName: name, operator: op), withInputs: [object, rhs]) + emit( + UpdateProperty(propertyName: name, operator: op), + withInputs: [object, rhs]) } else { - emit(SetProperty(propertyName: name, isGuarded: memberExpression.isOptional), withInputs: [object, rhs]) + emit( + SetProperty(propertyName: name, isGuarded: memberExpression.isOptional), + withInputs: [object, rhs]) } case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let index = Int64(exactly: literal.value) { + if case .numberLiteral(let literal) = expr.expression, + let index = Int64(exactly: literal.value) + { if let op = assignmentOperator { - emit(UpdateElement(index: index, operator: op), withInputs: [object, rhs]) + emit( + UpdateElement(index: index, operator: op), + withInputs: [object, rhs]) } else { emit(SetElement(index: index), withInputs: [object, rhs]) } } else { let property = try compileExpression(expr) if let op = assignmentOperator { - emit(UpdateComputedProperty(operator: op), withInputs: [object, property, rhs]) + emit( + UpdateComputedProperty(operator: op), + withInputs: [object, property, rhs]) } else { emit(SetComputedProperty(), withInputs: [object, property, rhs]) } @@ -757,18 +827,22 @@ public class JavaScriptCompiler { case .superMemberExpression(let superMemberExpression): guard superMemberExpression.isOptional == false else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super member expressions") } guard let property = superMemberExpression.property else { - throw CompilerError.invalidNodeError("Missing property in super member expression") + throw CompilerError.invalidNodeError( + "Missing property in super member expression") } switch property { case .name(let name): if let op = assignmentOperator { // Example: super.foo += 1 - emit(UpdateSuperProperty(propertyName: name, operator: op), withInputs: [rhs]) + emit( + UpdateSuperProperty(propertyName: name, operator: op), withInputs: [rhs] + ) } else { // Example: super.foo = 1 emit(SetSuperProperty(propertyName: name), withInputs: [rhs]) @@ -783,7 +857,9 @@ public class JavaScriptCompiler { case .identifier(let identifier): // Try to lookup the variable belonging to the identifier. If there is none, we're (probably) dealing with // an access to a global variable/builtin or a hoisted variable access. In the case, create a named variable. - let lhs = lookupIdentifier(identifier.name) ?? emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output + let lhs = + lookupIdentifier(identifier.name) + ?? emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output // Compile to a Reassign or Update operation switch assignmentExpression.operator { @@ -795,13 +871,15 @@ public class JavaScriptCompiler { // It's something like "+=", "-=", etc. let binaryOperator = String(assignmentExpression.operator.dropLast()) guard let op = BinaryOperator(rawValue: binaryOperator) else { - throw CompilerError.invalidNodeError("Unknown assignment operator \(assignmentExpression.operator)") + throw CompilerError.invalidNodeError( + "Unknown assignment operator \(assignmentExpression.operator)") } emit(Update(op), withInputs: [lhs, rhs]) } default: - throw CompilerError.unsupportedFeatureError("Compiler only supports assignments to object members or identifiers") + throw CompilerError.unsupportedFeatureError( + "Compiler only supports assignments to object members or identifiers") } return rhs @@ -812,20 +890,21 @@ public class JavaScriptCompiler { var computedKeys = [Variable]() for field in objectExpression.fields { guard let field = field.field else { - throw CompilerError.invalidNodeError("missing concrete field in object expression") + throw CompilerError.invalidNodeError( + "missing concrete field in object expression") } - let key : Compiler_Protobuf_PropertyKey + let key: Compiler_Protobuf_PropertyKey switch field { - case .property(let property): - propertyValues.append(try compileExpression(property.value)) - key = property.key - case .method(let method): - key = method.key - case .getter(let getter): - key = getter.key - case .setter(let setter): - key = setter.key + case .property(let property): + propertyValues.append(try compileExpression(property.value)) + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key } if case .expression(let expression) = key.body { computedKeys.append(try compileExpression(expression)) @@ -842,7 +921,8 @@ public class JavaScriptCompiler { switch field.field! { case .property(let property): guard let key = property.key.body else { - throw CompilerError.invalidNodeError("missing key in object expression field") + throw CompilerError.invalidNodeError( + "missing key in object expression field") } let inputs = [propertyValues.removeLast()] switch key { @@ -851,22 +931,30 @@ public class JavaScriptCompiler { case .index(let index): emit(ObjectLiteralAddElement(index: index), withInputs: inputs) case .expression: - emit(ObjectLiteralAddComputedProperty(), withInputs: [computedKeys.removeLast()] + inputs) + emit( + ObjectLiteralAddComputedProperty(), + withInputs: [computedKeys.removeLast()] + inputs) } case .method(let method): let parameters = convertParameters(method.parameters) let head: Instruction guard let key = method.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression method") + throw CompilerError.invalidNodeError( + "Missing key in object expression method") } switch key { case .name(let name): - head = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + head = emit( + BeginObjectLiteralMethod(methodName: name, parameters: parameters)) case .index(let index): - head = emit(BeginObjectLiteralMethod(methodName: String(index), parameters: parameters)) + head = emit( + BeginObjectLiteralMethod( + methodName: String(index), parameters: parameters)) case .expression: - head = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedMethod(parameters: parameters), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -886,7 +974,8 @@ public class JavaScriptCompiler { } case .getter(let getter): guard let key = getter.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression getter") + throw CompilerError.invalidNodeError( + "Missing key in object expression getter") } let head: Instruction switch key { @@ -895,7 +984,9 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralGetter(propertyName: String(index))) case .expression: - head = emit(BeginObjectLiteralComputedGetter(), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedGetter(), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { map("this", to: head.innerOutput) @@ -911,7 +1002,8 @@ public class JavaScriptCompiler { } case .setter(let setter): guard let key = setter.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression setter") + throw CompilerError.invalidNodeError( + "Missing key in object expression setter") } let head: Instruction switch key { @@ -920,7 +1012,9 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralSetter(propertyName: String(index))) case .expression: - head = emit(BeginObjectLiteralComputedSetter(), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedSetter(), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { var parameters = head.innerOutputs @@ -965,12 +1059,14 @@ public class JavaScriptCompiler { if spreads.contains(true) { return emit(CreateArrayWithSpread(spreads: spreads), withInputs: elements).output } else { - return emit(CreateArray(numInitialValues: elements.count), withInputs: elements).output + return emit(CreateArray(numInitialValues: elements.count), withInputs: elements) + .output } case .functionExpression(let functionExpression): let parameters = convertParameters(functionExpression.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation let name = functionExpression.name.isEmpty ? nil : functionExpression.name switch functionExpression.type { case .plain: @@ -983,7 +1079,8 @@ public class JavaScriptCompiler { functionBegin = BeginAsyncFunction(parameters: parameters, functionName: name) functionEnd = EndAsyncFunction() case .asyncGenerator: - functionBegin = BeginAsyncGeneratorFunction(parameters: parameters, functionName: name) + functionBegin = BeginAsyncGeneratorFunction( + parameters: parameters, functionName: name) functionEnd = EndAsyncGeneratorFunction() case .UNRECOGNIZED(let type): throw CompilerError.invalidNodeError("invalid function declaration type \(type)") @@ -1002,7 +1099,8 @@ public class JavaScriptCompiler { case .arrowFunctionExpression(let arrowFunction): let parameters = convertParameters(arrowFunction.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation switch arrowFunction.type { case .plain: functionBegin = BeginArrowFunction(parameters: parameters) @@ -1011,13 +1109,16 @@ public class JavaScriptCompiler { functionBegin = BeginAsyncArrowFunction(parameters: parameters) functionEnd = EndAsyncArrowFunction() default: - throw CompilerError.invalidNodeError("invalid arrow function type \(arrowFunction.type)") + throw CompilerError.invalidNodeError( + "invalid arrow function type \(arrowFunction.type)") } let instr = emit(functionBegin) try enterNewScope { mapParameters(arrowFunction.parameters, to: instr.innerOutputs) - guard let body = arrowFunction.body else { throw CompilerError.invalidNodeError("missing body in arrow function") } + guard let body = arrowFunction.body else { + throw CompilerError.invalidNodeError("missing body in arrow function") + } switch body { case .block(let block): try compileBody(block) @@ -1038,47 +1139,97 @@ public class JavaScriptCompiler { if case .memberExpression(let memberExpression) = callExpression.callee.expression { // obj.foo(...) or obj[expr](...) let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression in call expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError( + "missing property in member expression in call expression") + } switch property { case .name(let name): if isSpreading { - return emit(CallMethodWithSpread(methodName: name, numArguments: arguments.count, spreads: spreads, isGuarded: callExpression.isOptional), withInputs: [object] + arguments).output + return emit( + CallMethodWithSpread( + methodName: name, numArguments: arguments.count, spreads: spreads, + isGuarded: callExpression.isOptional), + withInputs: [object] + arguments + ).output } else { - return emit(CallMethod(methodName: name, numArguments: arguments.count, isGuarded: callExpression.isOptional), withInputs: [object] + arguments).output + return emit( + CallMethod( + methodName: name, numArguments: arguments.count, + isGuarded: callExpression.isOptional), + withInputs: [object] + arguments + ).output } case .expression(let expr): let method = try compileExpression(expr) if isSpreading { - return emit(CallComputedMethodWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: callExpression.isOptional), withInputs: [object, method] + arguments).output + return emit( + CallComputedMethodWithSpread( + numArguments: arguments.count, spreads: spreads, + isGuarded: callExpression.isOptional), + withInputs: [object, method] + arguments + ).output } else { - return emit(CallComputedMethod(numArguments: arguments.count, isGuarded: callExpression.isOptional), withInputs: [object, method] + arguments).output + return emit( + CallComputedMethod( + numArguments: arguments.count, isGuarded: callExpression.isOptional), + withInputs: [object, method] + arguments + ).output } } - } else if case .superMemberExpression(let superMemberExpression) = callExpression.callee.expression { + } else if case .superMemberExpression(let superMemberExpression) = callExpression.callee + .expression + { // super.foo(...) guard !isSpreading else { - throw CompilerError.unsupportedFeatureError("Spread calls with super are not supported") + throw CompilerError.unsupportedFeatureError( + "Spread calls with super are not supported") } guard case .name(let methodName) = superMemberExpression.property else { - throw CompilerError.invalidNodeError("Super method calls must use a property name") + throw CompilerError.invalidNodeError( + "Super method calls must use a property name") } guard !callExpression.isOptional else { - throw CompilerError.unsupportedFeatureError("Optional chaining with super method calls is not supported") + throw CompilerError.unsupportedFeatureError( + "Optional chaining with super method calls is not supported") + } + return emit( + CallSuperMethod(methodName: methodName, numArguments: arguments.count), + withInputs: arguments + ).output + // Now check if it is a V8 intrinsic function + } else if case .v8IntrinsicIdentifier(let v8Intrinsic) = callExpression.callee + .expression + { + guard !isSpreading else { + throw CompilerError.unsupportedFeatureError( + "Not currently supporting spread calls to V8 intrinsics") } - return emit(CallSuperMethod(methodName: methodName, numArguments: arguments.count), withInputs: arguments).output - // Now check if it is a V8 intrinsic function - } else if case .v8IntrinsicIdentifier(let v8Intrinsic) = callExpression.callee.expression { - guard !isSpreading else { throw CompilerError.unsupportedFeatureError("Not currently supporting spread calls to V8 intrinsics") } - let argsString = Array(repeating: "%@", count: arguments.count).joined(separator: ", ") - return emit(Eval("%\(v8Intrinsic.name)(\(argsString))", numArguments: arguments.count, hasOutput: true), withInputs: arguments).output - // Otherwise it's a regular function call + let argsString = Array(repeating: "%@", count: arguments.count).joined( + separator: ", ") + return emit( + Eval( + "%\(v8Intrinsic.name)(\(argsString))", numArguments: arguments.count, + hasOutput: true), withInputs: arguments + ).output + // Otherwise it's a regular function call } else { - guard !callExpression.isOptional else { throw CompilerError.unsupportedFeatureError("Not currently supporting optional chaining with function calls") } + guard !callExpression.isOptional else { + throw CompilerError.unsupportedFeatureError( + "Not currently supporting optional chaining with function calls") + } let callee = try compileExpression(callExpression.callee) if isSpreading { - return emit(CallFunctionWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + CallFunctionWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: false), + withInputs: [callee] + arguments + ).output } else { - return emit(CallFunction(numArguments: arguments.count, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + CallFunction(numArguments: arguments.count, isGuarded: false), + withInputs: [callee] + arguments + ).output } } @@ -1087,43 +1238,66 @@ public class JavaScriptCompiler { let isSpreading = spreads.contains(true) if isSpreading { - throw CompilerError.unsupportedFeatureError("Spread arguments are not supported in super constructor calls") + throw CompilerError.unsupportedFeatureError( + "Spread arguments are not supported in super constructor calls") } guard !callSuperConstructor.isOptional else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super constructor calls") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super constructor calls") } emit(CallSuperConstructor(numArguments: arguments.count), withInputs: arguments) // In JS, the result of calling the super constructor is just |this|, but in FuzzIL the operation doesn't have an output (because |this| is always available anyway) - return lookupIdentifier("this")! // we can force unwrap because |this| always exists in the context where |super| exists + return lookupIdentifier("this")! // we can force unwrap because |this| always exists in the context where |super| exists case .newExpression(let newExpression): let callee = try compileExpression(newExpression.callee) let (arguments, spreads) = try compileCallArguments(newExpression.arguments) let isSpreading = spreads.contains(true) if isSpreading { - return emit(ConstructWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + ConstructWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: false), + withInputs: [callee] + arguments + ).output } else { - return emit(Construct(numArguments: arguments.count, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + Construct(numArguments: arguments.count, isGuarded: false), + withInputs: [callee] + arguments + ).output } case .memberExpression(let memberExpression): let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError("missing property in member expression") + } switch property { case .name(let name): - return emit(GetProperty(propertyName: name, isGuarded: memberExpression.isOptional), withInputs: [object]).output + return emit( + GetProperty(propertyName: name, isGuarded: memberExpression.isOptional), + withInputs: [object] + ).output case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let index = Int64(exactly: literal.value) { - return emit(GetElement(index: index, isGuarded: memberExpression.isOptional), withInputs: [object]).output + if case .numberLiteral(let literal) = expr.expression, + let index = Int64(exactly: literal.value) + { + return emit( + GetElement(index: index, isGuarded: memberExpression.isOptional), + withInputs: [object] + ).output } else { let property = try compileExpression(expr) - return emit(GetComputedProperty(isGuarded: memberExpression.isOptional), withInputs: [object, property]).output + return emit( + GetComputedProperty(isGuarded: memberExpression.isOptional), + withInputs: [object, property] + ).output } } case .superMemberExpression(let superMemberExpression): guard superMemberExpression.isOptional == false else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super member expressions") } guard let property = superMemberExpression.property else { throw CompilerError.invalidNodeError("Missing property in super member expression") @@ -1134,8 +1308,11 @@ public class JavaScriptCompiler { return emit(GetSuperProperty(propertyName: name), withInputs: []).output case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let _ = Int64(exactly: literal.value) { - throw CompilerError.unsupportedFeatureError("GetElement is not supported in super member expressions") + if case .numberLiteral(let literal) = expr.expression, + Int64(exactly: literal.value) != nil + { + throw CompilerError.unsupportedFeatureError( + "GetElement is not supported in super member expressions") } else { let compiledProperty = try compileExpression(expr) return emit(GetComputedSuperProperty(), withInputs: [compiledProperty]).output @@ -1150,8 +1327,12 @@ public class JavaScriptCompiler { let argument = try compileExpression(unaryExpression.argument) return emit(Void_(), withInputs: [argument]).output } else if unaryExpression.operator == "delete" { - guard case .memberExpression(let memberExpression) = unaryExpression.argument.expression else { - throw CompilerError.invalidNodeError("delete operator must be applied to a member expression") + guard + case .memberExpression(let memberExpression) = unaryExpression.argument + .expression + else { + throw CompilerError.invalidNodeError( + "delete operator must be applied to a member expression") } let obj = try compileExpression(memberExpression.object) @@ -1191,7 +1372,8 @@ public class JavaScriptCompiler { } } else { guard let op = UnaryOperator(rawValue: unaryExpression.operator) else { - throw CompilerError.invalidNodeError("invalid unary operator: \(unaryExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid unary operator: \(unaryExpression.operator)") } let argument = try compileExpression(unaryExpression.argument) return emit(UnaryOperation(op), withInputs: [argument]).output @@ -1209,7 +1391,8 @@ public class JavaScriptCompiler { } else if binaryExpression.operator == "instanceof" { return emit(TestInstanceOf(), withInputs: [lhs, rhs]).output } else { - throw CompilerError.invalidNodeError("invalid binary operator: \(binaryExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid binary operator: \(binaryExpression.operator)") } case .updateExpression(let updateExpression): @@ -1221,7 +1404,8 @@ public class JavaScriptCompiler { stringOp += " " } guard let op = UnaryOperator(rawValue: stringOp) else { - throw CompilerError.invalidNodeError("invalid unary operator: \(updateExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid unary operator: \(updateExpression.operator)") } return emit(UnaryOperation(op), withInputs: [argument]).output @@ -1242,15 +1426,18 @@ public class JavaScriptCompiler { return try sequenceExpression.expressions.map({ try compileExpression($0) }).last! case .v8IntrinsicIdentifier: - fatalError("V8IntrinsicIdentifiers must be handled as part of their surrounding CallExpression") + fatalError( + "V8IntrinsicIdentifiers must be handled as part of their surrounding CallExpression" + ) case .awaitExpression(let awaitExpression): - // TODO await is also allowed at the top level of a module - if !contextAnalyzer.context.contains(.asyncFunction) { - throw CompilerError.invalidNodeError("`await` is currently only supported in async functions") - } - let argument = try compileExpression(awaitExpression.argument) - return emit(Await(), withInputs: [argument]).output + // TODO await is also allowed at the top level of a module + if !contextAnalyzer.context.contains(.asyncFunction) { + throw CompilerError.invalidNodeError( + "`await` is currently only supported in async functions") + } + let argument = try compileExpression(awaitExpression.argument) + return emit(Await(), withInputs: [argument]).output } } @@ -1266,7 +1453,7 @@ public class JavaScriptCompiler { return code.append(instr) } - private func enterNewScope(_ block: () throws -> ()) rethrows { + private func enterNewScope(_ block: () throws -> Void) rethrows { scopes.push([:]) try block() scopes.pop() @@ -1286,7 +1473,9 @@ public class JavaScriptCompiler { scopes.top[identifier] = v } - private func mapParameters(_ parameters: Compiler_Protobuf_Parameters, to variables: ArraySlice) { + private func mapParameters( + _ parameters: Compiler_Protobuf_Parameters, to variables: ArraySlice + ) { assert(parameters.parameters.count == variables.count) for (param, v) in zip(parameters.parameters, variables) { map(param.name, to: v) @@ -1294,7 +1483,8 @@ public class JavaScriptCompiler { } private func convertParameters(_ parameters: Compiler_Protobuf_Parameters) -> Parameters { - return Parameters(count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) + return Parameters( + count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) } /// Convenience accessor for the currently active scope. diff --git a/Sources/Fuzzilli/Compiler/JavaScriptParser.swift b/Sources/Fuzzilli/Compiler/JavaScriptParser.swift index f6a12f15d..a1dc29450 100644 --- a/Sources/Fuzzilli/Compiler/JavaScriptParser.swift +++ b/Sources/Fuzzilli/Compiler/JavaScriptParser.swift @@ -37,7 +37,8 @@ public class JavaScriptParser { // This will only work if the executor is node as we will need to use node modules. // The Parser/ subdirectory is copied verbatim into the module bundle, see Package.swift. - self.parserScriptPath = Bundle.module.path(forResource: "parser", ofType: "js", inDirectory: "Parser")! + self.parserScriptPath = Bundle.module.path( + forResource: "parser", ofType: "js", inDirectory: "Parser")! // Check if the parser works. If not, it's likely because its node.js dependencies have not been installed. do { @@ -49,7 +50,8 @@ public class JavaScriptParser { public func parse(_ path: String) throws -> AST { let astProtobufDefinitionPath = Bundle.module.path(forResource: "ast", ofType: "proto")! - let outputFilePath = FileManager.default.temporaryDirectory.path + "/" + UUID().uuidString + ".ast.proto" + let outputFilePath = + FileManager.default.temporaryDirectory.path + "/" + UUID().uuidString + ".ast.proto" try runParserScript(withArguments: [astProtobufDefinitionPath, path, outputFilePath]) let data = try Data(contentsOf: URL(fileURLWithPath: outputFilePath)) try FileManager.default.removeItem(atPath: outputFilePath) diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 28c7eaad4..d6fa2d311 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -106,23 +106,25 @@ public struct Configuration { // be imported due to disabled wasm capabilities in the fuzzer. public static let excludedWasmDirectory = "excluded_wasm_programs" - public init(arguments: [String] = [], - timeout: UInt32 = 250, - skipStartupTests: Bool = false, - logLevel: LogLevel = .info, - startupTests: [(String, ExpectedStartupTestResult)] = [], - minimizationLimit: Double = 0.0, - dropoutRate: Double = 0, - collectRuntimeTypes: Bool = false, - enableDiagnostics: Bool = false, - enableInspection: Bool = false, - staticCorpus: Bool = false, - tag: String? = nil, - isWasmEnabled: Bool = false, - storagePath: String? = nil, - forDifferentialFuzzing: Bool = false, - instanceId: Int = -1, - dumplingEnabled: Bool = false) { + public init( + arguments: [String] = [], + timeout: UInt32 = 250, + skipStartupTests: Bool = false, + logLevel: LogLevel = .info, + startupTests: [(String, ExpectedStartupTestResult)] = [], + minimizationLimit: Double = 0.0, + dropoutRate: Double = 0, + collectRuntimeTypes: Bool = false, + enableDiagnostics: Bool = false, + enableInspection: Bool = false, + staticCorpus: Bool = false, + tag: String? = nil, + isWasmEnabled: Bool = false, + storagePath: String? = nil, + forDifferentialFuzzing: Bool = false, + instanceId: Int = -1, + dumplingEnabled: Bool = false + ) { self.arguments = arguments self.timeout = timeout self.logLevel = logLevel @@ -137,11 +139,14 @@ public struct Configuration { self.isWasmEnabled = isWasmEnabled self.storagePath = storagePath self.forDifferentialFuzzing = forDifferentialFuzzing - self.diffConfig = dumplingEnabled ? DifferentialConfig.create(for: instanceId, storagePath: storagePath!) : nil + self.diffConfig = + dumplingEnabled + ? DifferentialConfig.create(for: instanceId, storagePath: storagePath!) : nil } public func getInstanceSpecificArguments(forReferenceRunner: Bool) -> [String] { - return diffConfig.map { [$0.getDumpFilenameParameter(isOptimized: !forReferenceRunner)] } ?? [] + return diffConfig.map { [$0.getDumpFilenameParameter(isOptimized: !forReferenceRunner)] } + ?? [] } } diff --git a/Sources/Fuzzilli/Corpus/BasicCorpus.swift b/Sources/Fuzzilli/Corpus/BasicCorpus.swift index 2c4c6041f..eaa03d526 100644 --- a/Sources/Fuzzilli/Corpus/BasicCorpus.swift +++ b/Sources/Fuzzilli/Corpus/BasicCorpus.swift @@ -75,7 +75,7 @@ public class BasicCorpus: ComponentBase, Collection, Corpus { return true } - public func add(_ program: Program, _ : ProgramAspects) { + public func add(_ program: Program, _: ProgramAspects) { addInternal(program) } diff --git a/Sources/Fuzzilli/Corpus/Corpus.swift b/Sources/Fuzzilli/Corpus/Corpus.swift index 366b2dccd..0d72afbd6 100644 --- a/Sources/Fuzzilli/Corpus/Corpus.swift +++ b/Sources/Fuzzilli/Corpus/Corpus.swift @@ -18,7 +18,7 @@ import Foundation /// It manages discovered programs, determines the next seed to target, /// and provides programs to be used in the splice mutators -public protocol Corpus : ComponentBase { +public protocol Corpus: ComponentBase { var size: Int { get } var isEmpty: Bool { get } @@ -54,7 +54,9 @@ extension Corpus { if fuzzer.config.enableInspection { // Except for one identifying them as part of the corpus - program.comments.add("Corpus entry #\(index) on instance \(fuzzer.id) with Corpus type \(name)", at: .header) + program.comments.add( + "Corpus entry #\(index) on instance \(fuzzer.id) with Corpus type \(name)", + at: .header) } } } diff --git a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift index 8bec46d77..bbc069983 100644 --- a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift +++ b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift @@ -22,7 +22,7 @@ public class MarkovCorpus: ComponentBase, Corpus { private var programExecutionQueue: [Program] = [] // For each edge encountered thus far, track which program initially discovered it - private var edgeMap: [UInt32:Program] = [:] + private var edgeMap: [UInt32: Program] = [:] // This scheduler tracks the total number of samples it has returned // This allows it to build an initial baseline by randomly selecting a program to mutate @@ -137,7 +137,9 @@ public class MarkovCorpus: ComponentBase, Corpus { // Applies dropout on otherwise valid samples, to ensure variety between instances // This will likely select some samples multiple times, which is acceptable as // it is proportional to how many infrquently hit edges the sample has - if val != 0 && val <= maxEdgeCountToFind && (probability(1 - dropoutRate) || programExecutionQueue.isEmpty) { + if val != 0 && val <= maxEdgeCountToFind + && (probability(1 - dropoutRate) || programExecutionQueue.isEmpty) + { if let prog = edgeMap[UInt32(i)] { programExecutionQueue.append(prog) } diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 677256f53..430169bb2 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -68,7 +68,6 @@ // b:35 // a1:1 - import Foundation // This class is implementing one public function relate(optimizedOutput, unoptimizedOutput). @@ -129,13 +128,15 @@ public final class DiffOracle { guard self.bytecodeOffset == reference.bytecodeOffset, self.functionId == reference.functionId, self.arguments.count == reference.arguments.count, - self.registers.count == reference.registers.count else { + self.registers.count == reference.registers.count + else { return false } // Logic: 'self' is the Optimized frame. It is allowed to have "" or "". func isMatch(_ optValue: String, unoptValue: String) -> Bool { - return optValue == "" || optValue == "" || optValue == unoptValue + return optValue == "" || optValue == "" + || optValue == unoptValue } if !isMatch(self.accumulator, unoptValue: reference.accumulator) { @@ -161,7 +162,9 @@ public final class DiffOracle { _ runningRegs: inout [String] ) -> Frame { - func parseValue(prefix: String, defaultValue: T, index: inout Int, conversion: (Substring) -> T) -> T { + func parseValue( + prefix: String, defaultValue: T, index: inout Int, conversion: (Substring) -> T + ) -> T { if index < frameArr.endIndex && frameArr[index].starts(with: prefix) { let value = conversion(frameArr[index].dropFirst(prefix.count)) index += 1 @@ -172,13 +175,13 @@ public final class DiffOracle { var i = frameArr.startIndex func parseFrameType(_ type: Substring) -> FrameType { switch type { - case "---I": .interpreter - case "---S": .sparkplug - case "---M": .maglev - case "---T": .turbofan - case "---D": .deoptTurbofan - default: - fatalError("Unknown frame type") + case "---I": .interpreter + case "---S": .sparkplug + case "---M": .maglev + case "---T": .turbofan + case "---D": .deoptTurbofan + default: + fatalError("Unknown frame type") } } @@ -186,11 +189,21 @@ public final class DiffOracle { i += 1 - let bytecodeOffset = parseValue(prefix: "b:", defaultValue: prevFrame?.bytecodeOffset ?? -1, index: &i){ Int($0)! } - let functionId = parseValue(prefix: "f:", defaultValue: prevFrame?.functionId ?? -1, index: &i){ Int($0)! } - let accumulator = parseValue(prefix: "x:", defaultValue: prevFrame?.accumulator ?? "", index: &i){ String($0) } - let argCount = parseValue(prefix: "n:", defaultValue: prevFrame?.arguments.count ?? -1, index: &i){ Int($0)! } - let regCount = parseValue(prefix: "m:", defaultValue: prevFrame?.registers.count ?? -1, index: &i){ Int($0)! } + let bytecodeOffset = parseValue( + prefix: "b:", defaultValue: prevFrame?.bytecodeOffset ?? -1, index: &i + ) { Int($0)! } + let functionId = parseValue( + prefix: "f:", defaultValue: prevFrame?.functionId ?? -1, index: &i + ) { Int($0)! } + let accumulator = parseValue( + prefix: "x:", defaultValue: prevFrame?.accumulator ?? "", index: &i + ) { String($0) } + let argCount = parseValue( + prefix: "n:", defaultValue: prevFrame?.arguments.count ?? -1, index: &i + ) { Int($0)! } + let regCount = parseValue( + prefix: "m:", defaultValue: prevFrame?.registers.count ?? -1, index: &i + ) { Int($0)! } func updateValues(prefix: String, requiredCount: Int, buffer: inout [String]) -> [String] { @@ -201,7 +214,8 @@ public final class DiffOracle { } while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { - let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1, omittingEmptySubsequences: false) + let data = frameArr[i].dropFirst(1).split( + separator: ":", maxSplits: 1, omittingEmptySubsequences: false) let number = Int(data[0])! let value = String(data[1]) @@ -215,12 +229,13 @@ public final class DiffOracle { let arguments = updateValues(prefix: "a", requiredCount: argCount, buffer: &runningArgs) let registers = updateValues(prefix: "r", requiredCount: regCount, buffer: &runningRegs) - let frame = Frame(bytecodeOffset: bytecodeOffset, - accumulator: accumulator, - arguments: arguments, - registers: registers, - functionId: functionId, - frameType: frameType) + let frame = Frame( + bytecodeOffset: bytecodeOffset, + accumulator: accumulator, + arguments: arguments, + registers: registers, + functionId: functionId, + frameType: frameType) return frame } @@ -235,7 +250,9 @@ public final class DiffOracle { let frames = split.split(separator: "") for frame in frames { - assert(frame.first?.starts(with: "---") == true, "Invalid frame header found: \(frame.first ?? "nil")") + assert( + frame.first?.starts(with: "---") == true, + "Invalid frame header found: \(frame.first ?? "nil")") prevFrame = parseDiffFrame(frame, prevFrame, &runningArgs, &runningRegs) frameArray.append(prevFrame!) @@ -254,7 +271,9 @@ public final class DiffOracle { print("--------------------------") print("[") for unoptFrame in unoptFrames { - if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset && unoptFrame.functionId == optFrame.functionId { + if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset + && unoptFrame.functionId == optFrame.functionId + { print(unoptFrame) } } diff --git a/Sources/Fuzzilli/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift index ce13aab1e..191c613cf 100644 --- a/Sources/Fuzzilli/Engines/FuzzEngine.swift +++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift @@ -32,8 +32,10 @@ public class FuzzEngine: ComponentBase { fatalError("Must be implemented by child classes") } - final func execute(_ rawProgram: Program, withTimeout timeout: UInt32? = nil) -> ExecutionOutcome { - let program : Program + final func execute(_ rawProgram: Program, withTimeout timeout: UInt32? = nil) + -> ExecutionOutcome + { + let program: Program do { // An optional post processor can reject a sample right away with // the postProcessRejectionError. @@ -49,41 +51,48 @@ public class FuzzEngine: ComponentBase { let execution = fuzzer.execute(program, withTimeout: timeout, purpose: .fuzzing) switch execution.outcome { - case .crashed(let termsig): - fuzzer.processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local, withExectime: execution.execTime) - program.contributors.generatedCrashingSample() - - case .differential: - fuzzer.processDifferential(program, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local) - program.contributors.generatedDifferentialSample() - - case .succeeded: - fuzzer.dispatchEvent(fuzzer.events.ValidProgramFound, data: program) - var isInteresting = false - if let aspects = fuzzer.evaluator.evaluate(execution) { - if fuzzer.config.enableInspection { - program.comments.add("Program may be interesting due to \(aspects)", at: .footer) - program.comments.add("RUNNER ARGS: \(fuzzer.runner.processArguments.joined(separator: " "))", at: .header) - } - isInteresting = fuzzer.processMaybeInteresting(program, havingAspects: aspects, origin: .local) + case .crashed(let termsig): + fuzzer.processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: .local, withExectime: execution.execTime) + program.contributors.generatedCrashingSample() + + case .differential: + fuzzer.processDifferential( + program, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local) + program.contributors.generatedDifferentialSample() + + case .succeeded: + fuzzer.dispatchEvent(fuzzer.events.ValidProgramFound, data: program) + var isInteresting = false + if let aspects = fuzzer.evaluator.evaluate(execution) { + if fuzzer.config.enableInspection { + program.comments.add( + "Program may be interesting due to \(aspects)", at: .footer) + program.comments.add( + "RUNNER ARGS: \(fuzzer.runner.processArguments.joined(separator: " "))", + at: .header) } - - if isInteresting { - program.contributors.generatedInterestingSample() - } else { - program.contributors.generatedValidSample() - } - - case .failed(_): - if fuzzer.config.enableDiagnostics { - program.comments.add("Stdout:\n" + execution.stdout, at: .footer) - } - fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: program) - program.contributors.generatedInvalidSample() - - case .timedOut: - fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: program) - program.contributors.generatedTimeOutSample() + isInteresting = fuzzer.processMaybeInteresting( + program, havingAspects: aspects, origin: .local) + } + + if isInteresting { + program.contributors.generatedInterestingSample() + } else { + program.contributors.generatedValidSample() + } + + case .failed(_): + if fuzzer.config.enableDiagnostics { + program.comments.add("Stdout:\n" + execution.stdout, at: .footer) + } + fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: program) + program.contributors.generatedInvalidSample() + + case .timedOut: + fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: program) + program.contributors.generatedTimeOutSample() } if fuzzer.config.enableDiagnostics { @@ -96,13 +105,16 @@ public class FuzzEngine: ComponentBase { private final func ensureDeterministicExecutionOutcomeForDiagnostic(of program: Program) { let execution1 = fuzzer.execute(program, purpose: .other) - let stdout1 = execution1.stdout, stderr1 = execution1.stderr + let stdout1 = execution1.stdout + let stderr1 = execution1.stderr let execution2 = fuzzer.execute(program, purpose: .other) switch (execution1.outcome, execution2.outcome) { case (.succeeded, .failed(_)), - (.failed(_), .succeeded): - let stdout2 = execution2.stdout, stderr2 = execution2.stderr - logger.warning(""" + (.failed(_), .succeeded): + let stdout2 = execution2.stdout + let stderr2 = execution2.stderr + logger.warning( + """ Non-deterministic execution detected for program \(fuzzer.lifter.lift(program)) // Stdout of first execution diff --git a/Sources/Fuzzilli/Engines/HybridEngine.swift b/Sources/Fuzzilli/Engines/HybridEngine.swift index 214ff67cb..3c57b68f4 100644 --- a/Sources/Fuzzilli/Engines/HybridEngine.swift +++ b/Sources/Fuzzilli/Engines/HybridEngine.swift @@ -57,11 +57,16 @@ public class HybridEngine: FuzzEngine { for template in self.fuzzer.programTemplates { let name = template.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Statistics.percentageOrNa(template.correctnessRate, 7) - let interestingSamplesRate = Statistics.percentageOrNa(template.interestingSamplesRate, 7) + let interestingSamplesRate = Statistics.percentageOrNa( + template.interestingSamplesRate, 7) let timeoutRate = Statistics.percentageOrNa(template.timeoutRate, 6) - let avgInstructionsAdded = String(format: "%.2f", template.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) + let avgInstructionsAdded = String( + format: "%.2f", template.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) let samplesGenerated = template.totalSamples - self.logger.verbose(" \(name) : Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions generated: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)") + self.logger.verbose( + " \(name) : Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions generated: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)" + ) } let totalOutcomes = self.outcomeCounts.values.reduce(0, +) @@ -69,13 +74,21 @@ public class HybridEngine: FuzzEngine { for outcome in CodeGenerationOutcome.allCases { let count = self.outcomeCounts[outcome]! let frequency = (Double(count) / Double(totalOutcomes)) * 100.0 - self.logger.verbose(" \(outcome.rawValue.rightPadded(toLength: 25)): \(String(format: "%.2f%%", frequency))") + self.logger.verbose( + " \(outcome.rawValue.rightPadded(toLength: 25)): \(String(format: "%.2f%%", frequency))" + ) } self.logger.verbose("Number of generated programs: \(self.programsGenerated)") - self.logger.verbose("Average programs size: \(self.totalInstructionsGenerated / self.programsGenerated)") - self.logger.verbose("Average percentage of guarded operations after code generation: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeGeneration.currentValue))%") - self.logger.verbose("Average percentage of guarded operations after code refining: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeRefining.currentValue))%") + self.logger.verbose( + "Average programs size: \(self.totalInstructionsGenerated / self.programsGenerated)" + ) + self.logger.verbose( + "Average percentage of guarded operations after code generation: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeGeneration.currentValue))%" + ) + self.logger.verbose( + "Average percentage of guarded operations after code refining: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeRefining.currentValue))%" + ) } } } @@ -99,7 +112,8 @@ public class HybridEngine: FuzzEngine { // Update basic codegen statistics. totalInstructionsGenerated += generatedProgram.size programsGenerated += 1 - percentageOfGuardedOperationsAfterCodeGeneration.add(computePercentageOfGuardedOperations(in: generatedProgram)) + percentageOfGuardedOperationsAfterCodeGeneration.add( + computePercentageOfGuardedOperations(in: generatedProgram)) // We use a higher timeout for the initial execution as pure code generation should only rarely lead to infinite loops/recursion. // On the other hand, the generated program may contain slow operations (e.g. try-catch guards) that the subsequent fixup may remove. @@ -125,7 +139,8 @@ public class HybridEngine: FuzzEngine { let refinedProgram: Program if let result = fixupMutator.mutate(generatedProgram, for: fuzzer) { refinedProgram = result - percentageOfGuardedOperationsAfterCodeRefining.add(computePercentageOfGuardedOperations(in: refinedProgram)) + percentageOfGuardedOperationsAfterCodeRefining.add( + computePercentageOfGuardedOperations(in: refinedProgram)) } else { // Fixup is expected to fail sometimes, for example if there is nothing to fix. refinedProgram = generatedProgram @@ -155,7 +170,8 @@ public class HybridEngine: FuzzEngine { } guard let program = mutatedProgram else { - logger.warning("Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") + logger.warning( + "Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") continue } diff --git a/Sources/Fuzzilli/Engines/MultiEngine.swift b/Sources/Fuzzilli/Engines/MultiEngine.swift index 2eab72945..625776291 100644 --- a/Sources/Fuzzilli/Engines/MultiEngine.swift +++ b/Sources/Fuzzilli/Engines/MultiEngine.swift @@ -29,7 +29,10 @@ public class MultiEngine: FuzzEngine { /// The number of fuzzing iterations. private var currentIteration = 0 - public init(engines: WeightedList, initialActive: FuzzEngine? = nil, iterationsPerEngine: Int) { + public init( + engines: WeightedList, initialActive: FuzzEngine? = nil, + iterationsPerEngine: Int + ) { assert(iterationsPerEngine > 0) self.iterationsPerEngine = iterationsPerEngine self.engines = engines @@ -49,7 +52,8 @@ public class MultiEngine: FuzzEngine { if currentIteration % iterationsPerEngine == 0 { let nextEngine = engines.randomElement() if nextEngine !== activeEngine { - logger.info("Switching active engine from \(activeEngine.name) to \(nextEngine.name)") + logger.info( + "Switching active engine from \(activeEngine.name) to \(nextEngine.name)") activeEngine = nextEngine } } diff --git a/Sources/Fuzzilli/Engines/MutationEngine.swift b/Sources/Fuzzilli/Engines/MutationEngine.swift index a02176bee..6975f8c77 100644 --- a/Sources/Fuzzilli/Engines/MutationEngine.swift +++ b/Sources/Fuzzilli/Engines/MutationEngine.swift @@ -67,7 +67,8 @@ public class MutationEngine: FuzzEngine { } guard let program = mutatedProgram else { - logger.warning("Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") + logger.warning( + "Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") continue } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index cb052d76f..05a1c753b 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -16,7 +16,9 @@ import Foundation public class JavaScriptEnvironment: ComponentBase { // Possible return values of the 'typeof' operator. - public static let jsTypeNames = ["undefined", "boolean", "number", "string", "symbol", "function", "object", "bigint"] + public static let jsTypeNames = [ + "undefined", "boolean", "number", "string", "symbol", "function", "object", "bigint", + ] // TODO: use it in all places where it can be used. public static let typedArrayConstructors = [ @@ -27,36 +29,45 @@ public class JavaScriptEnvironment: ComponentBase { // Integer values that are more likely to trigger edge-cases. public static let InterestingIntegers: [Int64] = [ - -9223372036854775808, -9223372036854775807, // Int64 min, mostly for BigInts - -9007199254740992, -9007199254740991, -9007199254740990, // Smallest integer value that is still precisely representable by a double - -4294967297, -4294967296, -4294967295, // Negative Uint32 max - -2147483649, -2147483648, -2147483647, // Int32 min - -1073741824, -536870912, -268435456, // -2**32 / {4, 8, 16} - -65537, -65536, -65535, // -2**16 - -4096, -1024, -256, -128, // Other powers of two - -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 - 127, 128, 129, // 2**7 - 255, 256, 257, // 2**8 - 512, 1000, 1024, 4096, 10000, // Misc numbers - 65535, 65536, 65537, // 2**16 - 268435439, 268435440, 268435441, // V8 String kMaxLength (32-bit) - 536870887, 536870888, 536870889, // V8 String kMaxLength (64-bit) - 268435456, 536870912, 1073741824, // 2**32 / {4, 8, 16} - 1073741823, 1073741824, 1073741825, // 2**30 - 2147483647, 2147483648, 2147483649, // Int32 max - 4294967295, 4294967296, 4294967297, // Uint32 max - 9007199254740990, 9007199254740991, 9007199254740992, // Biggest integer value that is still precisely representable by a double - 9223372036854775807, // Int64 max, mostly for BigInts - 0x3ffffffc, 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000002, // Numbers around smi max (2^30 - 1) - 0xbffffffd, 0xbfffffff, 0xc0000000, 0xc0000001, 0xc0000003 // Numbers around Smi min (-2^30) + -9_223_372_036_854_775_808, -9_223_372_036_854_775_807, // Int64 min, mostly for BigInts + -9_007_199_254_740_992, -9_007_199_254_740_991, -9_007_199_254_740_990, // Smallest integer value that is still precisely representable by a double + -4_294_967_297, -4_294_967_296, -4_294_967_295, // Negative Uint32 max + -2_147_483_649, -2_147_483_648, -2_147_483_647, // Int32 min + -1_073_741_824, -536_870_912, -268_435_456, // -2**32 / {4, 8, 16} + -65537, -65536, -65535, // -2**16 + -4096, -1024, -256, -128, // Other powers of two + -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 + 127, 128, 129, // 2**7 + 255, 256, 257, // 2**8 + 512, 1000, 1024, 4096, 10000, // Misc numbers + 65535, 65536, 65537, // 2**16 + 268_435_439, 268_435_440, 268_435_441, // V8 String kMaxLength (32-bit) + 536_870_887, 536_870_888, 536_870_889, // V8 String kMaxLength (64-bit) + 268_435_456, 536_870_912, 1_073_741_824, // 2**32 / {4, 8, 16} + 1_073_741_823, 1_073_741_824, 1_073_741_825, // 2**30 + 2_147_483_647, 2_147_483_648, 2_147_483_649, // Int32 max + 4_294_967_295, 4_294_967_296, 4_294_967_297, // Uint32 max + 9_007_199_254_740_990, 9_007_199_254_740_991, 9_007_199_254_740_992, // Biggest integer value that is still precisely representable by a double + 9_223_372_036_854_775_807, // Int64 max, mostly for BigInts + 0x3fff_fffc, 0x3fff_fffe, 0x3fff_ffff, 0x4000_0000, 0x4000_0002, // Numbers around smi max (2^30 - 1) + 0xbfff_fffd, 0xbfff_ffff, 0xc000_0000, 0xc000_0001, 0xc000_0003, // Numbers around Smi min (-2^30) ] - static let wellKnownSymbols = ["iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", "hasInstance", "isConcatSpreadable", "unscopables", "species", "toPrimitive", "toStringTag", "dispose", "asyncDispose"] + static let wellKnownSymbols = [ + "iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", + "hasInstance", "isConcatSpreadable", "unscopables", "species", "toPrimitive", "toStringTag", + "dispose", "asyncDispose", + ] public let interestingIntegers = InterestingIntegers // Double values that are more likely to trigger edge-cases. - public let interestingFloats = [-Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan] + public let interestingFloats = [ + -Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, + -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, + Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, + 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan, + ] // TODO more? public let interestingStrings = jsTypeNames + [""] @@ -65,227 +76,230 @@ public class JavaScriptEnvironment: ComponentBase { // https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/dicts/regexp.dict public let interestingRegExps = [ // These do *not* work with unicode or unicodeSets - (pattern: #"a\q"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[z-\d]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\11"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\111]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c!"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\11a]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c!]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c~]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\[\]\{\}\(\)\%\^\#\ "#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\[\]\{\}\(\)\%\^\#\ ]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\118"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\00011]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c~"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{,}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[-123]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[-\xf0\x9f\x92\xa9]+"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{,}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{12,"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?!a)?a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\111"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?!a)?a\1"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\1111]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c1]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){0,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\q"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\011"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\d-z]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\011]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\8"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\11a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\118]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\1112"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12,"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\d-\d]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\11"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)\4*"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?:(?=a))a\1"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c_"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)\4"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\x3z"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c_]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{1z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){1,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\1111"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\u003z"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\11]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\9"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){9,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[a-b-c]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a\q"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[z-\d]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{"#, incompatibleFlags: .unicode | .unicodeSets), + ( + pattern: #"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\11"#, + incompatibleFlags: .unicode | .unicodeSets + ), + (pattern: #"[\111]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c!"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\11a]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c!]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c~]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\[\]\{\}\(\)\%\^\#\ "#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\[\]\{\}\(\)\%\^\#\ ]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\118"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\00011]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c~"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{,}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[-123]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[-\xf0\x9f\x92\xa9]+"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{,}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{12,"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?!a)?a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\111"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?!a)?a\1"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\1111]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c1]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){0,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\q"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\011"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\d-z]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\011]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\8"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\11a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\118]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\1112"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12,"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\d-\d]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\11"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(x)(x)(x)\4*"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?:(?=a))a\1"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c_"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(x)(x)(x)\4"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\x3z"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c_]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{1z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){1,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\1111"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\u003z"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\11]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\9"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){9,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[a-b-c]"#, incompatibleFlags: .unicode | .unicodeSets), // These work with all flags - (pattern: #"(x)(x)(x)\1*"#, incompatibleFlags: .empty), - (pattern: #"\x01"#, incompatibleFlags: .empty), - (pattern: #"(?: foo )"#, incompatibleFlags: .empty), - (pattern: #"(ab|cde)"#, incompatibleFlags: .empty), - (pattern: #"foo|(bar|baz)|quux"#, incompatibleFlags: .empty), - (pattern: #"(?:a*)*"#, incompatibleFlags: .empty), - (pattern: #"a{0,1}?"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)?"#, incompatibleFlags: .empty), - (pattern: #"a$"#, incompatibleFlags: .empty), - (pattern: #"a(?=b)"#, incompatibleFlags: .empty), - (pattern: #"foo[z]*"#, incompatibleFlags: .empty), - (pattern: #"\u{12345}\u{23456}"#, incompatibleFlags: .empty), - (pattern: #"(?!(a))\1"#, incompatibleFlags: .empty), - (pattern: #"abc+?"#, incompatibleFlags: .empty), - (pattern: #"a*b"#, incompatibleFlags: .empty), - (pattern: #"(?:a?)*"#, incompatibleFlags: .empty), - (pattern: #"\xf0\x9f\x92\xa9"#, incompatibleFlags: .empty), - (pattern: #"a{1,2}?"#, incompatibleFlags: .empty), - (pattern: #"a\n"#, incompatibleFlags: .empty), - (pattern: #"\P{Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"(?=)"#, incompatibleFlags: .empty), - (pattern: #"\1(a)"#, incompatibleFlags: .empty), - (pattern: #"."#, incompatibleFlags: .empty), - (pattern: #"()"#, incompatibleFlags: .empty), - (pattern: #"(a)"#, incompatibleFlags: .empty), - (pattern: #"(?:a{5,1000000}){3,1000000}"#, incompatibleFlags: .empty), - (pattern: #"a\Sc"#, incompatibleFlags: .empty), - (pattern: #"a(?=b)c"#, incompatibleFlags: .empty), - (pattern: #"a{0}"#, incompatibleFlags: .empty), - (pattern: #"(?:a*)+"#, incompatibleFlags: .empty), - (pattern: #"\ud808\udf45*"#, incompatibleFlags: .empty), - (pattern: #"a\w"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)*"#, incompatibleFlags: .empty), - (pattern: #"a(?:b)"#, incompatibleFlags: .empty), - (pattern: #"(?<=a)"#, incompatibleFlags: .empty), - (pattern: #"(x)(x)(x)\3"#, incompatibleFlags: .empty), - (pattern: #"foo(?<=bar)baz"#, incompatibleFlags: .empty), - (pattern: #"\xe2\x81\xa3"#, incompatibleFlags: .empty), - (pattern: #"ab\b\d\bcd"#, incompatibleFlags: .empty), - (pattern: #"[\ca]"#, incompatibleFlags: .empty), - (pattern: #"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\xbf]"#, incompatibleFlags: .empty), - (pattern: #"\p{Script_Extensions=Greek}"#, incompatibleFlags: .empty), - (pattern: #"\cj\cJ\ci\cI\ck\cK"#, incompatibleFlags: .empty), - (pattern: #"a\fb\nc\rd\te\vf"#, incompatibleFlags: .empty), - (pattern: #"\p{General_Category=Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"\u{12345}"#, incompatibleFlags: .empty), - (pattern: #"a\b!"#, incompatibleFlags: .empty), - (pattern: #"a[^a]"#, incompatibleFlags: .empty), - (pattern: #"\1\2(a(?:\1(b\1\2))\2)\1"#, incompatibleFlags: .empty), - (pattern: #"(?:ab)+"#, incompatibleFlags: .empty), - (pattern: #"[^123]"#, incompatibleFlags: .empty), - (pattern: #"a(?!b)"#, incompatibleFlags: .empty), - (pattern: #"a\Bb"#, incompatibleFlags: .empty), - (pattern: #"(?:ab)?"#, incompatibleFlags: .empty), - (pattern: #"(?)"#, incompatibleFlags: .empty), - (pattern: #"(?.)"#, incompatibleFlags: .empty), - (pattern: #"[\cz]"#, incompatibleFlags: .empty), - (pattern: #"(x)(x)(x)\3*"#, incompatibleFlags: .empty), - (pattern: #"foo(?.)\k"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)+"#, incompatibleFlags: .empty), - (pattern: #"(?=.)"#, incompatibleFlags: .empty), - (pattern: #"\p{Changes_When_NFKC_Casefolded}"#, incompatibleFlags: .empty), - (pattern: #"a\sc"#, incompatibleFlags: .empty), - (pattern: #"a||bc"#, incompatibleFlags: .empty), - (pattern: #"a+b"#, incompatibleFlags: .empty), - (pattern: #"[\cZ]"#, incompatibleFlags: .empty), - (pattern: #"a|b"#, incompatibleFlags: .empty), - (pattern: #"\u0034"#, incompatibleFlags: .empty), - (pattern: #"\cA"#, incompatibleFlags: .empty), - (pattern: #"ab|c"#, incompatibleFlags: .empty), - (pattern: #"abc|def|ghi"#, incompatibleFlags: .empty), - (pattern: #"(?:ab|cde)"#, incompatibleFlags: .empty), - (pattern: #"xyz?"#, incompatibleFlags: .empty), - (pattern: #"[a-zA-Z0-9]"#, incompatibleFlags: .empty), - (pattern: #"(?:a?)?"#, incompatibleFlags: .empty), - (pattern: #"xyz{0,1}"#, incompatibleFlags: .empty), - (pattern: #"a\D"#, incompatibleFlags: .empty), - (pattern: #"(?!\1(a\1)\1)\1"#, incompatibleFlags: .empty), - (pattern: #"a\bc"#, incompatibleFlags: .empty), - (pattern: #"\P{gc=Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"\b"#, incompatibleFlags: .empty), - (pattern: #"[x]"#, incompatibleFlags: .empty), - (pattern: #"(?:ab){4,7}"#, incompatibleFlags: .empty), - (pattern: #"a??"#, incompatibleFlags: .empty), - (pattern: #"(?(?(?(?.).).).)"#, incompatibleFlags: .empty), - (pattern: #"[\xe2\x81\xa3]"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\1*"#, incompatibleFlags: .empty), + (pattern: #"\x01"#, incompatibleFlags: .empty), + (pattern: #"(?: foo )"#, incompatibleFlags: .empty), + (pattern: #"(ab|cde)"#, incompatibleFlags: .empty), + (pattern: #"foo|(bar|baz)|quux"#, incompatibleFlags: .empty), + (pattern: #"(?:a*)*"#, incompatibleFlags: .empty), + (pattern: #"a{0,1}?"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)?"#, incompatibleFlags: .empty), + (pattern: #"a$"#, incompatibleFlags: .empty), + (pattern: #"a(?=b)"#, incompatibleFlags: .empty), + (pattern: #"foo[z]*"#, incompatibleFlags: .empty), + (pattern: #"\u{12345}\u{23456}"#, incompatibleFlags: .empty), + (pattern: #"(?!(a))\1"#, incompatibleFlags: .empty), + (pattern: #"abc+?"#, incompatibleFlags: .empty), + (pattern: #"a*b"#, incompatibleFlags: .empty), + (pattern: #"(?:a?)*"#, incompatibleFlags: .empty), + (pattern: #"\xf0\x9f\x92\xa9"#, incompatibleFlags: .empty), + (pattern: #"a{1,2}?"#, incompatibleFlags: .empty), + (pattern: #"a\n"#, incompatibleFlags: .empty), + (pattern: #"\P{Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"(?=)"#, incompatibleFlags: .empty), + (pattern: #"\1(a)"#, incompatibleFlags: .empty), + (pattern: #"."#, incompatibleFlags: .empty), + (pattern: #"()"#, incompatibleFlags: .empty), + (pattern: #"(a)"#, incompatibleFlags: .empty), + (pattern: #"(?:a{5,1000000}){3,1000000}"#, incompatibleFlags: .empty), + (pattern: #"a\Sc"#, incompatibleFlags: .empty), + (pattern: #"a(?=b)c"#, incompatibleFlags: .empty), + (pattern: #"a{0}"#, incompatibleFlags: .empty), + (pattern: #"(?:a*)+"#, incompatibleFlags: .empty), + (pattern: #"\ud808\udf45*"#, incompatibleFlags: .empty), + (pattern: #"a\w"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)*"#, incompatibleFlags: .empty), + (pattern: #"a(?:b)"#, incompatibleFlags: .empty), + (pattern: #"(?<=a)"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\3"#, incompatibleFlags: .empty), + (pattern: #"foo(?<=bar)baz"#, incompatibleFlags: .empty), + (pattern: #"\xe2\x81\xa3"#, incompatibleFlags: .empty), + (pattern: #"ab\b\d\bcd"#, incompatibleFlags: .empty), + (pattern: #"[\ca]"#, incompatibleFlags: .empty), + (pattern: #"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\xbf]"#, incompatibleFlags: .empty), + (pattern: #"\p{Script_Extensions=Greek}"#, incompatibleFlags: .empty), + (pattern: #"\cj\cJ\ci\cI\ck\cK"#, incompatibleFlags: .empty), + (pattern: #"a\fb\nc\rd\te\vf"#, incompatibleFlags: .empty), + (pattern: #"\p{General_Category=Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"\u{12345}"#, incompatibleFlags: .empty), + (pattern: #"a\b!"#, incompatibleFlags: .empty), + (pattern: #"a[^a]"#, incompatibleFlags: .empty), + (pattern: #"\1\2(a(?:\1(b\1\2))\2)\1"#, incompatibleFlags: .empty), + (pattern: #"(?:ab)+"#, incompatibleFlags: .empty), + (pattern: #"[^123]"#, incompatibleFlags: .empty), + (pattern: #"a(?!b)"#, incompatibleFlags: .empty), + (pattern: #"a\Bb"#, incompatibleFlags: .empty), + (pattern: #"(?:ab)?"#, incompatibleFlags: .empty), + (pattern: #"(?)"#, incompatibleFlags: .empty), + (pattern: #"(?.)"#, incompatibleFlags: .empty), + (pattern: #"[\cz]"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\3*"#, incompatibleFlags: .empty), + (pattern: #"foo(?.)\k"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)+"#, incompatibleFlags: .empty), + (pattern: #"(?=.)"#, incompatibleFlags: .empty), + (pattern: #"\p{Changes_When_NFKC_Casefolded}"#, incompatibleFlags: .empty), + (pattern: #"a\sc"#, incompatibleFlags: .empty), + (pattern: #"a||bc"#, incompatibleFlags: .empty), + (pattern: #"a+b"#, incompatibleFlags: .empty), + (pattern: #"[\cZ]"#, incompatibleFlags: .empty), + (pattern: #"a|b"#, incompatibleFlags: .empty), + (pattern: #"\u0034"#, incompatibleFlags: .empty), + (pattern: #"\cA"#, incompatibleFlags: .empty), + (pattern: #"ab|c"#, incompatibleFlags: .empty), + (pattern: #"abc|def|ghi"#, incompatibleFlags: .empty), + (pattern: #"(?:ab|cde)"#, incompatibleFlags: .empty), + (pattern: #"xyz?"#, incompatibleFlags: .empty), + (pattern: #"[a-zA-Z0-9]"#, incompatibleFlags: .empty), + (pattern: #"(?:a?)?"#, incompatibleFlags: .empty), + (pattern: #"xyz{0,1}"#, incompatibleFlags: .empty), + (pattern: #"a\D"#, incompatibleFlags: .empty), + (pattern: #"(?!\1(a\1)\1)\1"#, incompatibleFlags: .empty), + (pattern: #"a\bc"#, incompatibleFlags: .empty), + (pattern: #"\P{gc=Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"\b"#, incompatibleFlags: .empty), + (pattern: #"[x]"#, incompatibleFlags: .empty), + (pattern: #"(?:ab){4,7}"#, incompatibleFlags: .empty), + (pattern: #"a??"#, incompatibleFlags: .empty), + (pattern: #"(?(?(?(?.).).).)"#, incompatibleFlags: .empty), + (pattern: #"[\xe2\x81\xa3]"#, incompatibleFlags: .empty), ] public let interestingRegExpQuantifiers = ["*", "+", "?"] @@ -302,7 +316,6 @@ public class JavaScriptEnvironment: ComponentBase { public private(set) var builtinProperties = Set() public private(set) var builtinMethods = Set() - // Something that can generate a variable public typealias EnvironmentValueGenerator = (ProgramBuilder) -> Variable @@ -311,7 +324,8 @@ public class JavaScriptEnvironment: ComponentBase { private var enums: [String: ILType] = [:] // Producing generators, keyed on `type.group` - private var producingGenerators: [String: (generator: EnvironmentValueGenerator, probability: Double)] = [:] + private var producingGenerators: + [String: (generator: EnvironmentValueGenerator, probability: Double)] = [:] // Named string generators, keyed on `type.group` private var namedStringGenerators: [String: () -> String] = [:] private var producingMethods: [ILType: [(group: String, method: String)]] = [:] @@ -341,7 +355,10 @@ public class JavaScriptEnvironment: ComponentBase { static let propertyIndex = try! Regex("^(\(index))$") } - public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { + public init( + additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], + additionalEnumerations: [ILType] = [] + ) { super.init(name: "JavaScriptEnvironment") @@ -393,7 +410,11 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsAsyncDisposableStackConstructor) registerObjectGroup(.jsArrayBuffers) registerObjectGroup(.jsSharedArrayBuffers) - for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { + for variant in [ + "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", + "BigUint64Array", + ] { registerObjectGroup(.jsTypedArrays(variant)) registerObjectGroup(.jsTypedArrayPrototype(variant)) registerObjectGroup(.jsTypedArrayConstructor(variant)) @@ -426,7 +447,10 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsArrayBufferPrototype) registerObjectGroup(.jsSharedArrayBufferConstructor) registerObjectGroup(.jsSharedArrayBufferPrototype) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "AggregateError", "URIError", "SuppressedError"] { + for variant in [ + "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", + "AggregateError", "URIError", "SuppressedError", + ] { registerObjectGroup(.jsError(variant)) registerObjectGroup(.jsErrorPrototype(variant)) registerObjectGroup(.jsErrorConstructor(variant)) @@ -595,44 +619,80 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsIntlLocaleMatcherSettings) registerOptionsBag(.jsIteratorZipSettings) - registerTemporalFieldsObject(.jsTemporalPlainTimeLikeObject, forWith: false, dateFields: false, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateLikeObject, forWith: false, dateFields: true, timeFields: false, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateLikeObjectForWith, forWith: true, dateFields: true, timeFields: false, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateTimeLikeObjectForWith, forWith: true, dateFields: true, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalZonedDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, zonedFields: true) - registerTemporalFieldsObject(.jsTemporalZonedDateTimeLikeObjectForWith, forWith: true, dateFields: true, timeFields: true, zonedFields: true) + registerTemporalFieldsObject( + .jsTemporalPlainTimeLikeObject, forWith: false, dateFields: false, timeFields: true, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateLikeObject, forWith: false, dateFields: true, timeFields: false, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateLikeObjectForWith, forWith: true, dateFields: true, + timeFields: false, zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateTimeLikeObjectForWith, forWith: true, dateFields: true, + timeFields: true, zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalZonedDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, + zonedFields: true) + registerTemporalFieldsObject( + .jsTemporalZonedDateTimeLikeObjectForWith, forWith: true, dateFields: true, + timeFields: true, zonedFields: true) // This isn't a normal "temporal fields object" but is similar, and needs a similar producing generator registerObjectGroup(.jsTemporalDurationLikeObject) - addProducingGenerator(forType: ObjectGroup.jsTemporalDurationLikeObject.instanceType, with: { b in b.createTemporalDurationFieldsObject() }) - addNamedStringGenerator(forType: ObjectGroup.jsTemporalTimeZoneLike, - with: { - if Bool.random() { - return ProgramBuilder.randomTimeZoneString() - } else { - return ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: true) - } - }) - addNamedStringGenerator(forType: .jsIntlLocaleString, with: { ProgramBuilder.constructIntlLocaleString() }) - addNamedStringGenerator(forType: .jsIntlLanguageString, with: { ProgramBuilder.constructIntlLanguageString() }) - addNamedStringGenerator(forType: .jsIntlScriptString, with: { ProgramBuilder.constructIntlScriptString() }) - addNamedStringGenerator(forType: .jsIntlRegionString, with: { ProgramBuilder.constructIntlRegionString() }) - addNamedStringGenerator(forType: .jsIntlVariantString, with: { ProgramBuilder.constructIntlVariantString() }) - addNamedStringGenerator(forType: .jsIntlUnitString, with: { ProgramBuilder.constructIntlUnit() }) + addProducingGenerator( + forType: ObjectGroup.jsTemporalDurationLikeObject.instanceType, + with: { b in b.createTemporalDurationFieldsObject() }) + addNamedStringGenerator( + forType: ObjectGroup.jsTemporalTimeZoneLike, + with: { + if Bool.random() { + return ProgramBuilder.randomTimeZoneString() + } else { + return ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: true) + } + }) + addNamedStringGenerator( + forType: .jsIntlLocaleString, with: { ProgramBuilder.constructIntlLocaleString() }) + addNamedStringGenerator( + forType: .jsIntlLanguageString, with: { ProgramBuilder.constructIntlLanguageString() }) + addNamedStringGenerator( + forType: .jsIntlScriptString, with: { ProgramBuilder.constructIntlScriptString() }) + addNamedStringGenerator( + forType: .jsIntlRegionString, with: { ProgramBuilder.constructIntlRegionString() }) + addNamedStringGenerator( + forType: .jsIntlVariantString, with: { ProgramBuilder.constructIntlVariantString() }) + addNamedStringGenerator( + forType: .jsIntlUnitString, with: { ProgramBuilder.constructIntlUnit() }) // Temporal types are produced by a large number of methods; which means findOrGenerateType(), when asked to produce // a Temporal type, will tend towards trying to call a method on another Temporal type, which needs more Temporal types, // leading to a large amount of code generated. We do wish to test these codepaths as well, but by and large we // just want a freshly generated type. - addProducingGenerator(forType: .jsTemporalInstant, with: { $0.constructTemporalInstant() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalDuration, with: { $0.constructTemporalDuration() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainTime, with: { $0.constructTemporalTime() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainYearMonth, with: { $0.constructTemporalYearMonth() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainMonthDay, with: { $0.constructTemporalMonthDay() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainDate, with: { $0.constructTemporalDate() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainDateTime, with: { $0.constructTemporalDateTime() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalZonedDateTime, with: { $0.constructTemporalZonedDateTime() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalInstant, with: { $0.constructTemporalInstant() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalDuration, with: { $0.constructTemporalDuration() }, probability: 0.9 + ) + addProducingGenerator( + forType: .jsTemporalPlainTime, with: { $0.constructTemporalTime() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainYearMonth, with: { $0.constructTemporalYearMonth() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainMonthDay, with: { $0.constructTemporalMonthDay() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainDate, with: { $0.constructTemporalDate() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainDateTime, with: { $0.constructTemporalDateTime() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalZonedDateTime, with: { $0.constructTemporalZonedDateTime() }, + probability: 0.9) // Register builtins that should be available for fuzzing. // Here it is easy to selectively disable/enable some APIs for fuzzing by @@ -647,12 +707,19 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("Iterator", ofType: .jsIteratorConstructor) registerBuiltin("BigInt", ofType: .jsBigIntConstructor) registerBuiltin("RegExp", ofType: .jsRegExpConstructor) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError", "AggregateError"] { + for variant in [ + "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", + "URIError", "SuppressedError", "AggregateError", + ] { registerBuiltin(variant, ofType: .jsErrorConstructor(variant)) } registerBuiltin("ArrayBuffer", ofType: .jsArrayBufferConstructor) registerBuiltin("SharedArrayBuffer", ofType: .jsSharedArrayBufferConstructor) - for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { + for variant in [ + "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", + "BigUint64Array", + ] { registerBuiltin(variant, ofType: .jsTypedArrayConstructor(variant)) } registerBuiltin("DataView", ofType: .jsDataViewConstructor) @@ -713,25 +780,31 @@ public class JavaScriptEnvironment: ComponentBase { logger.info("Initialized static JS environment model") logger.info("Have \(builtins.count) available builtins: \(builtins.sorted())") logger.info("Have \(groups.count) different object groups: \(groups.keys.sorted())") - logger.info("Have \(builtinProperties.count) builtin property names: \(builtinProperties.sorted())") + logger.info( + "Have \(builtinProperties.count) builtin property names: \(builtinProperties.sorted())") logger.info("Have \(builtinMethods.count) builtin method names: \(builtinMethods.sorted())") - logger.info("Have \(customProperties.count) custom property names: \(customProperties.sorted())") + logger.info( + "Have \(customProperties.count) custom property names: \(customProperties.sorted())") logger.info("Have \(customMethods.count) custom method names: \(customMethods.sorted())") - logger.info("Have \(customPrivateMethods.count) custom private method names: \(customPrivateMethods.sorted())") + logger.info( + "Have \(customPrivateMethods.count) custom private method names: \(customPrivateMethods.sorted())" + ) } func checkConstructorAvailability() { logger.info("Checking constructor availability...") // These constructors return types that are well-known instead of .object types. let knownExceptions = [ - "Boolean", // returns .boolean - "Number", // returns .number - "Object", // returns plain .object - "Proxy", // returns .jsAnything + "Boolean", // returns .boolean + "Number", // returns .number + "Object", // returns plain .object + "Proxy", // returns .jsAnything ] for builtin in builtins where type(ofBuiltin: builtin).Is(.constructor()) { if knownExceptions.contains(builtin) { continue } - if !hasGroup(builtin) { logger.warning("Missing group info for constructable \(builtin)")} + if !hasGroup(builtin) { + logger.warning("Missing group info for constructable \(builtin)") + } if type(ofBuiltin: builtin).signature == nil { logger.warning("Missing signature for builtin \(builtin)") } else { @@ -764,25 +837,36 @@ public class JavaScriptEnvironment: ComponentBase { // - Temporal objects: These can be obtained from the result of other API calls, however a // a lot of these API calls need more Temporal objects, leading to runaway recursion attempting // to generate a large number of Temporal objects. Instead, we bias heavily towards the producing generator. - public func addProducingGenerator(forType type: ILType, with generator: @escaping EnvironmentValueGenerator, probability: Double = 1.0) { - assert(type.Is(.object()), "Producing generators can only be registered for objects, found \(type)") + public func addProducingGenerator( + forType type: ILType, with generator: @escaping EnvironmentValueGenerator, + probability: Double = 1.0 + ) { + assert( + type.Is(.object()), + "Producing generators can only be registered for objects, found \(type)") producingGenerators[type.group!] = (generator, probability) } // Register a generator for a custom named string. - public func addNamedStringGenerator(forType type: ILType, with generator: @escaping () -> String) { - assert(type.Is(.string), "Named string generators can only be registered for strings, found \(type)") + public func addNamedStringGenerator( + forType type: ILType, with generator: @escaping () -> String + ) { + assert( + type.Is(.string), + "Named string generators can only be registered for strings, found \(type)") namedStringGenerators[type.group!] = generator } private func addProducingMethod(forType type: ILType, by method: String, on group: String) { if producingMethods[type] == nil { - producingMethods[type] = [] + producingMethods[type] = [] } producingMethods[type]! += [(group: group, method: method)] } - @discardableResult private func addProducingProperty(forType type: ILType, by property: String, on group: String) -> ILType { + @discardableResult private func addProducingProperty( + forType type: ILType, by property: String, on group: String + ) -> ILType { let actualType: ILType if type.Is(.constructor()) { actualType = type.signature!.outputType @@ -825,8 +909,9 @@ public class JavaScriptEnvironment: ComponentBase { // for overloads in group.methods { for method in overloads.value { - assert(method.outputType != .nothing, - "Method \(overloads.key) in group \(group.name) has .nothing as outputType") + assert( + method.outputType != .nothing, + "Method \(overloads.key) in group \(group.name) has .nothing as outputType") if method.outputType == .undefined { continue } @@ -836,7 +921,8 @@ public class JavaScriptEnvironment: ComponentBase { if var current = groups[groupName] { while let parent = current.parent { current = groups[parent]! - addProducingMethod(forType: current.instanceType, by: overloads.key, on: group.name) + addProducingMethod( + forType: current.instanceType, by: overloads.key, on: group.name) } } } @@ -847,12 +933,14 @@ public class JavaScriptEnvironment: ComponentBase { // Step 3: Initialize `producingProperties` // for property in group.properties { - let producedType = addProducingProperty(forType: property.value, by: property.key, on: group.name) + let producedType = addProducingProperty( + forType: property.value, by: property.key, on: group.name) if let groupName = producedType.group { if var current = groups[groupName] { while let parent = current.parent { current = groups[parent]! - addProducingProperty(forType: current.instanceType, by: property.key, on: group.name) + addProducingProperty( + forType: current.instanceType, by: property.key, on: group.name) } } } @@ -862,11 +950,17 @@ public class JavaScriptEnvironment: ComponentBase { // Temporal has a large number of "fields" object (aka "partial temporal objects" or "temporal-like objects") // which have a number of datetime-like fields. These are never produced as a result from any JS APIs, so we cannot // expect instances of them to already exist in scope. Instead, we generate them ourselves when requested. - public func registerTemporalFieldsObject(_ group: ObjectGroup, forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool) { + public func registerTemporalFieldsObject( + _ group: ObjectGroup, forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool + ) { registerObjectGroup(group) - addProducingGenerator(forType: group.instanceType, with: { b in - b.createTemporalFieldsObject(forWith: forWith, dateFields: dateFields, timeFields: timeFields, zonedFields: zonedFields) - }) + addProducingGenerator( + forType: group.instanceType, + with: { b in + b.createTemporalFieldsObject( + forWith: forWith, dateFields: dateFields, timeFields: timeFields, + zonedFields: zonedFields) + }) } public func registerBuiltin(_ name: String, ofType type: ILType) { @@ -875,14 +969,14 @@ public class JavaScriptEnvironment: ComponentBase { builtins.insert(name) let producedType = addProducingProperty(forType: type, by: name, on: "") - if let groupName = producedType.group { - if var current = groups[groupName] { - while let parent = current.parent { - current = groups[parent]! - addProducingProperty(forType: current.instanceType, by: name, on: "") - } + if let groupName = producedType.group { + if var current = groups[groupName] { + while let parent = current.parent { + current = groups[parent]! + addProducingProperty(forType: current.instanceType, by: name, on: "") } } + } } public func registerOptionsBag(_ bag: OptionsBag) { @@ -890,11 +984,15 @@ public class JavaScriptEnvironment: ComponentBase { for property in bag.properties.values { if property.isEnumeration { - assert(enums[property.group!] != nil, "Enum \(property.group!) used in options bag but not registered on the JavaScriptEnvironment") + assert( + enums[property.group!] != nil, + "Enum \(property.group!) used in options bag but not registered on the JavaScriptEnvironment" + ) } } - addProducingGenerator(forType: bag.group.instanceType, with: { b in b.createOptionsBag(bag) }) + addProducingGenerator( + forType: bag.group.instanceType, with: { b in b.createOptionsBag(bag) }) } public func type(ofBuiltin builtinName: String) -> ILType { @@ -906,7 +1004,7 @@ public class JavaScriptEnvironment: ComponentBase { } } - public func type (ofGroup groupName: String) -> ILType { + public func type(ofGroup groupName: String) -> ILType { if let type = groups[groupName]?.instanceType { return type } else { @@ -961,8 +1059,10 @@ public class JavaScriptEnvironment: ComponentBase { // For ObjectGroups, get a generator that is registered as being able to produce this // ObjectGroup. - public func getProducingGenerator(ofType type: ILType) -> (generator: EnvironmentValueGenerator, probability: Double)? { - type.group.flatMap {producingGenerators[$0]} + public func getProducingGenerator(ofType type: ILType) -> ( + generator: EnvironmentValueGenerator, probability: Double + )? { + type.group.flatMap { producingGenerators[$0] } } // For named strings, get a generator that is registered as being able to produce this @@ -971,7 +1071,6 @@ public class JavaScriptEnvironment: ComponentBase { namedStringGenerators[name] } - // If the object group refers to a constructor, get its path. public func getPathIfConstructor(ofGroup groupName: String) -> [String]? { guard let group = groups[groupName] else { @@ -1026,7 +1125,10 @@ public struct ObjectGroup { /// The type of instances of this group. public var instanceType: ILType - public init(name: String, constructorPath: String? = nil, instanceType: ILType?, properties: [String: ILType], overloads: [String: [Signature]], parent: String? = nil) { + public init( + name: String, constructorPath: String? = nil, instanceType: ILType?, + properties: [String: ILType], overloads: [String: [Signature]], parent: String? = nil + ) { self.name = name self.properties = properties self.methods = overloads @@ -1037,24 +1139,39 @@ public struct ObjectGroup { // (which would then need some kind of fallback ObjectGroup that is consulted by the // type lookup routines if the real group doesn't have the requested information). assert(instanceType.group == name, "group name mismatch for group \(name)") - assert(instanceType.properties == Set(properties.keys), "inconsistent property information for object group \(name): \(Set(properties.keys).symmetricDifference(instanceType.properties))") - assert(instanceType.methods == Set(methods.keys), "inconsistent method information for object group \(name): \(Set(methods.keys).symmetricDifference(instanceType.methods))") + assert( + instanceType.properties == Set(properties.keys), + "inconsistent property information for object group \(name): \(Set(properties.keys).symmetricDifference(instanceType.properties))" + ) + assert( + instanceType.methods == Set(methods.keys), + "inconsistent method information for object group \(name): \(Set(methods.keys).symmetricDifference(instanceType.methods))" + ) self.instanceType = instanceType } else { // Simply calculate the instance type based on the ObjectGroup information. - self.instanceType = .object(ofGroup: name, withProperties: Array(properties.keys), withMethods: Array(methods.keys)) + self.instanceType = .object( + ofGroup: name, withProperties: Array(properties.keys), + withMethods: Array(methods.keys)) } if let constructorPath { - assert(self.instanceType.Is(.constructor()) || self.instanceType.Is(.function()), "\(name) has a constructor path set but does not wrap a constructor") + assert( + self.instanceType.Is(.constructor()) || self.instanceType.Is(.function()), + "\(name) has a constructor path set but does not wrap a constructor") self.constructorPath = constructorPath.split(separator: ".").map({ String($0) }) } else { self.constructorPath = nil } } - public init(name: String, constructorPath: String? = nil, instanceType: ILType?, properties: [String: ILType], methods: [String: Signature], parent: String? = nil) { - self.init(name: name, constructorPath: constructorPath, instanceType: instanceType, properties: properties, overloads: methods.mapValues({[$0]}), parent: parent) + public init( + name: String, constructorPath: String? = nil, instanceType: ILType?, + properties: [String: ILType], methods: [String: Signature], parent: String? = nil + ) { + self.init( + name: name, constructorPath: constructorPath, instanceType: instanceType, + properties: properties, overloads: methods.mapValues({ [$0] }), parent: parent) } } @@ -1072,15 +1189,17 @@ public struct OptionsBag { self.properties = properties let properties = properties.mapValues { // This list can be expanded over time as long as createOptionsBag() supports this - assert($0.isEnumeration || $0.Is(.number | .integer | .boolean | .iterable) || + assert( + $0.isEnumeration || $0.Is(.number | .integer | .boolean | .iterable) // Has a producing generator registered - $0.Is(.jsTemporalPlainTime) || + || $0.Is(.jsTemporalPlainTime) // Has explicit support in createOptionsBag - $0.Is(OptionsBag.jsTemporalRelativeTo), - "Found unsupported option type \($0) in options bag \(name)") - return $0 | .undefined; + || $0.Is(OptionsBag.jsTemporalRelativeTo), + "Found unsupported option type \($0) in options bag \(name)") + return $0 | .undefined } - self.group = ObjectGroup(name: name, instanceType: nil, properties: properties, overloads: [:]) + self.group = ObjectGroup( + name: name, instanceType: nil, properties: properties, overloads: [:]) } } @@ -1100,77 +1219,170 @@ public struct OptionsBag { // // Note, these must be kept in sync with the ObjectGroups below (in particular the properties and methods). To help with that, the ObjectGroup // constructor asserts that the type information is consistent between instance type and the ObjectGroup. -public extension ILType { +extension ILType { /// Type of a string in JavaScript. /// A JS string is both a string and an object on which methods can be called. - static let jsString = ILType.string + ILType.iterable + ILType.object(ofGroup: "String", withProperties: ["length"], withMethods: ["charAt", "charCodeAt", "codePointAt", "concat", "includes", "endsWith", "indexOf", "lastIndexOf", "match", "matchAll", "padEnd", "padStart", "normalize", "repeat", "replace", "replaceAll", "search", "slice", "split", "startsWith", "substring", "trim", "trimStart", "trimLeft", "trimEnd", "trimRight" ,"toUpperCase", "toLowerCase", "localeCompare", "anchor", "at", "big", "blink", "bold", "fixed", "fontcolor", "fontsize", "isWellFormed", "italics", "link", "small", "strike", "sub", "substr", "sup", "toLocaleLowerCase", "toLocaleUpperCase", "toWellFormed"]) + public static let jsString = + ILType.string + ILType.iterable + + ILType.object( + ofGroup: "String", withProperties: ["length"], + withMethods: [ + "charAt", "charCodeAt", "codePointAt", "concat", "includes", "endsWith", "indexOf", + "lastIndexOf", "match", "matchAll", "padEnd", "padStart", "normalize", "repeat", + "replace", "replaceAll", "search", "slice", "split", "startsWith", "substring", + "trim", "trimStart", "trimLeft", "trimEnd", "trimRight", "toUpperCase", + "toLowerCase", "localeCompare", "anchor", "at", "big", "blink", "bold", "fixed", + "fontcolor", "fontsize", "isWellFormed", "italics", "link", "small", "strike", + "sub", "substr", "sup", "toLocaleLowerCase", "toLocaleUpperCase", "toWellFormed", + ]) /// Type of a regular expression in JavaScript. /// A JS RegExp is both a RegExp and an object on which methods can be called. - static let jsRegExp = ILType.regexp + ILType.object(ofGroup: "RegExp", withProperties: ["flags", "dotAll", "global", "ignoreCase", "multiline", "source", "sticky", "unicode"], withMethods: ["compile", "exec", "test"]) + public static let jsRegExp = + ILType.regexp + + ILType.object( + ofGroup: "RegExp", + withProperties: [ + "flags", "dotAll", "global", "ignoreCase", "multiline", "source", "sticky", + "unicode", + ], withMethods: ["compile", "exec", "test"]) /// Type of a JavaScript Symbol. - static let jsSymbol = ILType.object(ofGroup: "Symbol", withProperties: ["description"]) + public static let jsSymbol = ILType.object(ofGroup: "Symbol", withProperties: ["description"]) /// Type of a JavaScript array. - static let jsArray = ILType.iterable + ILType.object(ofGroup: "Array", withProperties: ["length"], withMethods: ["at", "concat", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", "toReversed", "toSorted", "toSpliced", "with", "join", "lastIndexOf", "values", "flat", "flatMap"]) + public static let jsArray = + ILType.iterable + + ILType.object( + ofGroup: "Array", withProperties: ["length"], + withMethods: [ + "at", "concat", "copyWithin", "fill", "find", "findIndex", "findLast", + "findLastIndex", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", + "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", + "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", + "toReversed", "toSorted", "toSpliced", "with", "join", "lastIndexOf", "values", + "flat", "flatMap", + ]) /// Type of a JavaScript function's arguments object. - static let jsArguments = ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) + public static let jsArguments = + ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) /// Type of a JavaScript Iterator object. - static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"]) + public static let jsIterator = + ILType.iterable + + ILType.object( + ofGroup: "Iterator", withProperties: ["value", "done"], + withMethods: [ + "next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", + "toArray", "forEach", "some", "every", "find", + ]) /// Type of the JavaScript Iterator constructor builtin. - static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from", "concat", "zip"]) + public static let jsIteratorConstructor = ILType.object( + ofGroup: "IteratorConstructor", withProperties: ["prototype"], + withMethods: ["from", "concat", "zip"]) /// Type of a JavaScript generator object. - static let jsGenerator = ILType.iterable + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) + public static let jsGenerator = + ILType.iterable + + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) /// Type of a JavaScript Promise object. - static let jsPromise = ILType.object(ofGroup: "Promise", withMethods: ["catch", "finally", "then"]) + public static let jsPromise = ILType.object( + ofGroup: "Promise", withMethods: ["catch", "finally", "then"]) /// Type of a JavaScript Map object. - static let jsMap = ILType.iterable + ILType.object(ofGroup: "Map", withProperties: ["size"], withMethods: ["clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values", "getOrInsert", "getOrInsertComputed"]) + public static let jsMap = + ILType.iterable + + ILType.object( + ofGroup: "Map", withProperties: ["size"], + withMethods: [ + "clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values", + "getOrInsert", "getOrInsertComputed", + ]) /// Type of a JavaScript WeakMap object. - static let jsWeakMap = ILType.object(ofGroup: "WeakMap", withMethods: ["delete", "get", "has", "set", "getOrInsert", "getOrInsertComputed"]) + public static let jsWeakMap = ILType.object( + ofGroup: "WeakMap", + withMethods: ["delete", "get", "has", "set", "getOrInsert", "getOrInsertComputed"]) /// Type of a JavaScript Set object. - static let jsSet = ILType.iterable + ILType.object(ofGroup: "Set", withProperties: ["size"], withMethods: ["add", "clear", "delete", "entries", "forEach", "has", "keys", "values", "difference", "intersection", "isDisjointFrom", "isSubsetOf", "isSupersetOf", "symmetricDifference", "union"]) + public static let jsSet = + ILType.iterable + + ILType.object( + ofGroup: "Set", withProperties: ["size"], + withMethods: [ + "add", "clear", "delete", "entries", "forEach", "has", "keys", "values", + "difference", "intersection", "isDisjointFrom", "isSubsetOf", "isSupersetOf", + "symmetricDifference", "union", + ]) /// Type of a JavaScript WeakSet object. - static let jsWeakSet = ILType.object(ofGroup: "WeakSet", withMethods: ["add", "delete", "has"]) + public static let jsWeakSet = ILType.object( + ofGroup: "WeakSet", withMethods: ["add", "delete", "has"]) /// Type of a JavaScript WeakRef object. - static let jsWeakRef = ILType.object(ofGroup: "WeakRef", withMethods: ["deref"]) + public static let jsWeakRef = ILType.object(ofGroup: "WeakRef", withMethods: ["deref"]) /// Type of a JavaScript FinalizationRegistry object. - static let jsFinalizationRegistry = ILType.object(ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) + public static let jsFinalizationRegistry = ILType.object( + ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) /// Type of a JavaScript DisposableStack object. - static let jsDisposableStack = ILType.object(ofGroup: "DisposableStack", withProperties: ["disposed"], withMethods: ["dispose", "use", "adopt", "defer", "move"]) + public static let jsDisposableStack = ILType.object( + ofGroup: "DisposableStack", withProperties: ["disposed"], + withMethods: ["dispose", "use", "adopt", "defer", "move"]) /// Type of a JavaScript AsyncDisposableStack object. - static let jsAsyncDisposableStack = ILType.object(ofGroup: "AsyncDisposableStack", withProperties: ["disposed"], withMethods: ["disposeAsync", "use", "adopt", "defer", "move"]) + public static let jsAsyncDisposableStack = ILType.object( + ofGroup: "AsyncDisposableStack", withProperties: ["disposed"], + withMethods: ["disposeAsync", "use", "adopt", "defer", "move"]) /// Type of a JavaScript ArrayBuffer object. - static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "sliceToImmutable", "transfer", "transferToFixedLength", "transferToImmutable"]) + public static let jsArrayBuffer = ILType.object( + ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], + withMethods: [ + "resize", "slice", "sliceToImmutable", "transfer", "transferToFixedLength", + "transferToImmutable", + ]) /// Type of a JavaScript SharedArrayBuffer object. - static let jsSharedArrayBuffer = ILType.object(ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], withMethods: ["grow", "slice"]) + public static let jsSharedArrayBuffer = ILType.object( + ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], + withMethods: ["grow", "slice"]) /// Type of a JavaScript DataView object. - static let jsDataView = ILType.object(ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], withMethods: ["getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", "getFloat32", "getFloat64", "getBigInt64", "getBigUint64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", "setFloat64", "setBigInt64", "setBigUint64"]) + public static let jsDataView = ILType.object( + ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], + withMethods: [ + "getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", + "getFloat32", "getFloat64", "getBigInt64", "getBigUint64", "setInt8", "setUint8", + "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", + "setFloat64", "setBigInt64", "setBigUint64", + ]) /// Type of a JavaScript TypedArray object of the given variant. - static func jsTypedArray(_ variant: String) -> ILType { - let extraMethods = variant == "Uint8Array" ? ["setFromBase64", "setFromHex", "toBase64", "toHex"] : [] - return .iterable + .object(ofGroup: variant, withProperties: ["BYTES_PER_ELEMENT", "buffer", "byteOffset", "byteLength", "length"], withMethods: ["at", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", "reverse", "slice", "sort", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "set", "some", "subarray", "reduce", "reduceRight", "join", "lastIndexOf", "values", "toLocaleString", "toString", "toReversed", "toSorted", "with"] - + extraMethods) + public static func jsTypedArray(_ variant: String) -> ILType { + let extraMethods = + variant == "Uint8Array" ? ["setFromBase64", "setFromHex", "toBase64", "toHex"] : [] + return .iterable + + .object( + ofGroup: variant, + withProperties: [ + "BYTES_PER_ELEMENT", "buffer", "byteOffset", "byteLength", "length", + ], + withMethods: [ + "at", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", + "reverse", "slice", "sort", "includes", "indexOf", "keys", "entries", "forEach", + "filter", "map", "every", "set", "some", "subarray", "reduce", "reduceRight", + "join", "lastIndexOf", "values", "toLocaleString", "toString", "toReversed", + "toSorted", "with", + ] + + extraMethods) } - static let jsUint8Array = jsTypedArray("Uint8Array") + public static let jsUint8Array = jsTypedArray("Uint8Array") // TODO(mliedtke): Saying "any typed array" isn't really easily possible right now, so we type // the expected parameter type as any object. @@ -1178,49 +1390,103 @@ public extension ILType { /// Type of a JavaScript function. /// A JavaScript function is also constructors. Moreover, it is also an object as it has a number of properties and methods. - static func jsFunction(_ signature: Signature = Signature.forUnknownFunction) -> ILType { - return .constructor(signature) + .function(signature) + .object(ofGroup: "Function", withProperties: ["prototype", "length", "arguments", "caller", "name"], withMethods: ["apply", "bind", "call"]) + public static func jsFunction(_ signature: Signature = Signature.forUnknownFunction) -> ILType { + return .constructor(signature) + .function(signature) + + .object( + ofGroup: "Function", + withProperties: ["prototype", "length", "arguments", "caller", "name"], + withMethods: ["apply", "bind", "call"]) } /// Type of the JavaScript Object constructor builtin. - static let jsObjectConstructor = .functionAndConstructor([.jsAnything...] => .object()) + .object(ofGroup: "ObjectConstructor", withProperties: ["prototype"], withMethods: ["assign", "fromEntries", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "values", "groupBy", "hasOwn"]) + public static let jsObjectConstructor = + .functionAndConstructor([.jsAnything...] => .object()) + + .object( + ofGroup: "ObjectConstructor", withProperties: ["prototype"], + withMethods: [ + "assign", "fromEntries", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", + "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", + "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", + "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", + "values", "groupBy", "hasOwn", + ]) /// Type of the JavaScript Array constructor builtin. - static let jsArrayConstructor = .functionAndConstructor([.integer] => .jsArray) + .object(ofGroup: "ArrayConstructor", withProperties: ["prototype"], withMethods: ["from", "fromAsync", "of", "isArray"]) + public static let jsArrayConstructor = + .functionAndConstructor([.integer] => .jsArray) + + .object( + ofGroup: "ArrayConstructor", withProperties: ["prototype"], + withMethods: ["from", "fromAsync", "of", "isArray"]) /// Type of the JavaScript Function constructor builtin. - static let jsFunctionConstructor = ILType.constructor([.string] => .jsFunction(Signature.forUnknownFunction)) + .object(ofGroup: "FunctionConstructor", withProperties: ["prototype"]) + public static let jsFunctionConstructor = + ILType.constructor([.string] => .jsFunction(Signature.forUnknownFunction)) + + .object(ofGroup: "FunctionConstructor", withProperties: ["prototype"]) /// Type of the JavaScript String constructor builtin. - static let jsStringConstructor = ILType.functionAndConstructor([.jsAnything] => .jsString) + .object(ofGroup: "StringConstructor", withProperties: ["prototype"], withMethods: ["fromCharCode", "fromCodePoint", "raw"]) + public static let jsStringConstructor = + ILType.functionAndConstructor([.jsAnything] => .jsString) + + .object( + ofGroup: "StringConstructor", withProperties: ["prototype"], + withMethods: ["fromCharCode", "fromCodePoint", "raw"]) /// Type of the JavaScript Boolean constructor builtin. - static let jsBooleanConstructor = ILType.functionAndConstructor([.jsAnything] => .boolean) + .object(ofGroup: "BooleanConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsBooleanConstructor = + ILType.functionAndConstructor([.jsAnything] => .boolean) + + .object(ofGroup: "BooleanConstructor", withProperties: ["prototype"], withMethods: []) /// Type of the JavaScript Number constructor builtin. - static let jsNumberConstructor = ILType.functionAndConstructor([.jsAnything] => .number) + .object(ofGroup: "NumberConstructor", withProperties: ["prototype", "EPSILON", "MAX_SAFE_INTEGER", "MAX_VALUE", "MIN_SAFE_INTEGER", "MIN_VALUE", "NaN", "NEGATIVE_INFINITY", "POSITIVE_INFINITY"], withMethods: ["isNaN", "isFinite", "isInteger", "isSafeInteger", "parseFloat", "parseInt"]) + public static let jsNumberConstructor = + ILType.functionAndConstructor([.jsAnything] => .number) + + .object( + ofGroup: "NumberConstructor", + withProperties: [ + "prototype", "EPSILON", "MAX_SAFE_INTEGER", "MAX_VALUE", "MIN_SAFE_INTEGER", + "MIN_VALUE", "NaN", "NEGATIVE_INFINITY", "POSITIVE_INFINITY", + ], + withMethods: [ + "isNaN", "isFinite", "isInteger", "isSafeInteger", "parseFloat", "parseInt", + ]) /// Type of the JavaScript Symbol constructor builtin. - static let jsSymbolConstructor = ILType.function([.string] => .jsSymbol) + .object(ofGroup: "SymbolConstructor", withProperties: JavaScriptEnvironment.wellKnownSymbols, withMethods: ["for", "keyFor"]) + public static let jsSymbolConstructor = + ILType.function([.string] => .jsSymbol) + + .object( + ofGroup: "SymbolConstructor", withProperties: JavaScriptEnvironment.wellKnownSymbols, + withMethods: ["for", "keyFor"]) /// Type of the JavaScript BigInt constructor builtin. - static let jsBigIntConstructor = ILType.function([.number] => .bigint) + .object(ofGroup: "BigIntConstructor", withProperties: ["prototype"], withMethods: ["asIntN", "asUintN"]) + public static let jsBigIntConstructor = + ILType.function([.number] => .bigint) + + .object( + ofGroup: "BigIntConstructor", withProperties: ["prototype"], + withMethods: ["asIntN", "asUintN"]) /// Type of the JavaScript RegExp constructor builtin. - static let jsRegExpConstructor = ILType.functionAndConstructor([.string] => .jsRegExp) + .object(ofGroup: "RegExpConstructor", withProperties: ["prototype", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$_", "input", "lastMatch", "lastParen", "leftContext"], withMethods: ["escape"]) + public static let jsRegExpConstructor = + ILType.functionAndConstructor([.string] => .jsRegExp) + + .object( + ofGroup: "RegExpConstructor", + withProperties: [ + "prototype", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$_", "input", + "lastMatch", "lastParen", "leftContext", + ], withMethods: ["escape"]) /// Type of a JavaScript Error object of the given variant. - static func jsError(_ variant: String) -> ILType { - return .object(ofGroup: variant, withProperties: ["message", "name", "cause", "stack"], withMethods: ["toString"]) + public static func jsError(_ variant: String) -> ILType { + return .object( + ofGroup: variant, withProperties: ["message", "name", "cause", "stack"], + withMethods: ["toString"]) } /// Type of the JavaScript Error constructor builtin - static func jsErrorConstructor(_ variant: String) -> ILType { - let signature = if variant == "AggregateError" { - [.plain(.iterable), .opt(.string), .opt(.object())] => .jsError("AggregateError") - } else { - [.opt(.string)] => .jsError(variant) - } + public static func jsErrorConstructor(_ variant: String) -> ILType { + let signature = + if variant == "AggregateError" { + [.plain(.iterable), .opt(.string), .opt(.object())] => .jsError("AggregateError") + } else { + [.opt(.string)] => .jsError(variant) + } return .functionAndConstructor(signature) + .object( ofGroup: "\(variant)Constructor", @@ -1229,16 +1495,25 @@ public extension ILType { } /// Type of the JavaScript ArrayBuffer constructor builtin. - static let jsArrayBufferConstructor = ILType.constructor([.integer, .opt(.object())] => .jsArrayBuffer) + .object(ofGroup: "ArrayBufferConstructor", withProperties: ["prototype"], withMethods: ["isView"]) + public static let jsArrayBufferConstructor = + ILType.constructor([.integer, .opt(.object())] => .jsArrayBuffer) + + .object( + ofGroup: "ArrayBufferConstructor", withProperties: ["prototype"], + withMethods: ["isView"]) /// Type of the JavaScript SharedArrayBuffer constructor builtin. - static let jsSharedArrayBufferConstructor = ILType.constructor([.integer, .opt(.object())] => .jsSharedArrayBuffer) + .object(ofGroup: "SharedArrayBufferConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsSharedArrayBufferConstructor = + ILType.constructor([.integer, .opt(.object())] => .jsSharedArrayBuffer) + + .object( + ofGroup: "SharedArrayBufferConstructor", withProperties: ["prototype"], withMethods: []) /// Type of a JavaScript TypedArray constructor builtin. - static func jsTypedArrayConstructor(_ variant: String) -> ILType { + public static func jsTypedArrayConstructor(_ variant: String) -> ILType { let methods = variant == "Uint8Array" ? ["fromBase64", "fromHex"] : [] // TODO Also allow SharedArrayBuffers for first argument - return .constructor([.opt(.integer | .jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsTypedArray(variant)) + return .constructor( + [.opt(.integer | .jsArrayBuffer), .opt(.integer), .opt(.integer)] + => .jsTypedArray(variant)) + .object( ofGroup: "\(variant)Constructor", withProperties: ["prototype", "BYTES_PER_ELEMENT"], @@ -1246,141 +1521,233 @@ public extension ILType { } /// Type of the JavaScript DataView constructor builtin. (TODO Also allow SharedArrayBuffers for first argument) - static let jsDataViewConstructor = ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) + public static let jsDataViewConstructor = + ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Promise constructor builtin. - static let jsPromiseConstructor = ILType.constructor([.function()] => .jsPromise) + .object(ofGroup: "PromiseConstructor", withProperties: ["prototype"], withMethods: ["resolve", "reject", "all", "any", "race", "allSettled", "try", "withResolvers"]) + public static let jsPromiseConstructor = + ILType.constructor([.function()] => .jsPromise) + + .object( + ofGroup: "PromiseConstructor", withProperties: ["prototype"], + withMethods: [ + "resolve", "reject", "all", "any", "race", "allSettled", "try", "withResolvers", + ]) /// Type of the JavaScript Proxy constructor builtin. - static let jsProxyConstructor = ILType.constructor([.object(), .object()] => .jsAnything) + .object(ofGroup: "ProxyConstructor", withProperties: [], withMethods: ["revocable"]) + public static let jsProxyConstructor = + ILType.constructor([.object(), .object()] => .jsAnything) + + .object(ofGroup: "ProxyConstructor", withProperties: [], withMethods: ["revocable"]) /// Type of the JavaScript Map constructor builtin. - static let jsMapConstructor = ILType.constructor([.object()] => .jsMap) + .object(ofGroup: "MapConstructor", withProperties: ["prototype"], withMethods: ["groupBy"]) + public static let jsMapConstructor = + ILType.constructor([.object()] => .jsMap) + + .object( + ofGroup: "MapConstructor", withProperties: ["prototype"], withMethods: ["groupBy"]) /// Type of the JavaScript WeakMap constructor builtin. - static let jsWeakMapConstructor = ILType.constructor([.object()] => .jsWeakMap) + .object(ofGroup: "WeakMapConstructor", withProperties: ["prototype"]) + public static let jsWeakMapConstructor = + ILType.constructor([.object()] => .jsWeakMap) + + .object(ofGroup: "WeakMapConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Set constructor builtin. - static let jsSetConstructor = ILType.constructor([.object()] => .jsSet) + .object(ofGroup: "SetConstructor", withProperties: ["prototype"]) + public static let jsSetConstructor = + ILType.constructor([.object()] => .jsSet) + + .object(ofGroup: "SetConstructor", withProperties: ["prototype"]) /// Type of the JavaScript WeakSet constructor builtin. - static let jsWeakSetConstructor = ILType.constructor([.object()] => .jsWeakSet) + .object(ofGroup: "WeakSetConstructor", withProperties: ["prototype"]) + public static let jsWeakSetConstructor = + ILType.constructor([.object()] => .jsWeakSet) + + .object(ofGroup: "WeakSetConstructor", withProperties: ["prototype"]) /// Type of the JavaScript WeakRef constructor builtin. - static let jsWeakRefConstructor = ILType.constructor([.object()] => .jsWeakRef) + .object(ofGroup: "WeakRefConstructor", withProperties: ["prototype"]) + public static let jsWeakRefConstructor = + ILType.constructor([.object()] => .jsWeakRef) + + .object(ofGroup: "WeakRefConstructor", withProperties: ["prototype"]) /// Type of the JavaScript FinalizationRegistry constructor builtin. - static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) + public static let jsFinalizationRegistryConstructor = + ILType.constructor([.function()] => .jsFinalizationRegistry) + + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) /// Type of the JavaScript DisposableStack constructor builtin. - static let jsDisposableStackConstructor = ILType.constructor([] => .jsDisposableStack) + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) + public static let jsDisposableStackConstructor = + ILType.constructor([] => .jsDisposableStack) + + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) /// Type of the JavaScript AsyncDisposableStack constructor builtin. - static let jsAsyncDisposableStackConstructor = ILType.constructor([] => .jsAsyncDisposableStack) + .object(ofGroup: "AsyncDisposableStackConstructor", withProperties: ["prototype"]) + public static let jsAsyncDisposableStackConstructor = + ILType.constructor([] => .jsAsyncDisposableStack) + + .object(ofGroup: "AsyncDisposableStackConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Math constructor builtin. - static let jsMathObject = ILType.object(ofGroup: "Math", withProperties: ["E", "PI", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"], withMethods: ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) + public static let jsMathObject = ILType.object( + ofGroup: "Math", + withProperties: ["E", "PI", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"], + withMethods: [ + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", + "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "f16round", "hypot", "imul", + "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", + "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc", + ]) /// Type of the JavaScript Atomics builtin. - static let jsAtomicsObject = ILType.object(ofGroup: "Atomics", withProperties: [], withMethods: ["add", "and", "compareExchange", "exchange", "isLockFree", "load", "notify", "or", "pause", "store", "sub", "wait", "waitAsync", "xor"]) + public static let jsAtomicsObject = ILType.object( + ofGroup: "Atomics", withProperties: [], + withMethods: [ + "add", "and", "compareExchange", "exchange", "isLockFree", "load", "notify", "or", + "pause", "store", "sub", "wait", "waitAsync", "xor", + ]) /// Type of the JavaScript Date object - static let jsDate = ILType.object(ofGroup: "Date", withMethods: ["toISOString", "toDateString", "toTimeString", "toLocaleString", "toLocaleDateString", "toLocaleTimeString", "getTime", "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "getTimezoneOffset", "getYear", "setTime", "setMilliseconds", "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "setYear", "toJSON", "toUTCString", "toGMTString", "toTemporalInstant"]) + public static let jsDate = ILType.object( + ofGroup: "Date", + withMethods: [ + "toISOString", "toDateString", "toTimeString", "toLocaleString", "toLocaleDateString", + "toLocaleTimeString", "getTime", "getFullYear", "getUTCFullYear", "getMonth", + "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", + "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", + "getMilliseconds", "getUTCMilliseconds", "getTimezoneOffset", "getYear", "setTime", + "setMilliseconds", "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", + "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth", + "setUTCMonth", "setFullYear", "setUTCFullYear", "setYear", "toJSON", "toUTCString", + "toGMTString", "toTemporalInstant", + ]) /// Type of the JavaScript Date constructor builtin - static let jsDateConstructor = ILType.functionAndConstructor([.opt(.string | .number)] => .jsDate) + .object(ofGroup: "DateConstructor", withProperties: ["prototype"], withMethods: ["UTC", "now", "parse"]) + public static let jsDateConstructor = + ILType.functionAndConstructor([.opt(.string | .number)] => .jsDate) + + .object( + ofGroup: "DateConstructor", withProperties: ["prototype"], + withMethods: ["UTC", "now", "parse"]) /// Type of the JavaScript JSON object builtin. - static let jsJSONObject = ILType.object(ofGroup: "JSON", withMethods: ["parse", "stringify", "rawJSON", "isRawJSON"]) + public static let jsJSONObject = ILType.object( + ofGroup: "JSON", withMethods: ["parse", "stringify", "rawJSON", "isRawJSON"]) /// Type of the JavaScript Reflect object builtin. - static let jsReflectObject = ILType.object(ofGroup: "Reflect", withMethods: ["apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"]) + public static let jsReflectObject = ILType.object( + ofGroup: "Reflect", + withMethods: [ + "apply", "construct", "defineProperty", "deleteProperty", "get", + "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", + "preventExtensions", "set", "setPrototypeOf", + ]) /// Type of the JavaScript isNaN builtin function. - static let jsIsNaNFunction = ILType.function([.jsAnything] => .boolean) + public static let jsIsNaNFunction = ILType.function([.jsAnything] => .boolean) /// Type of the JavaScript isFinite builtin function. - static let jsIsFiniteFunction = ILType.function([.jsAnything] => .boolean) + public static let jsIsFiniteFunction = ILType.function([.jsAnything] => .boolean) /// Type of the JavaScript escape builtin function. - static let jsEscapeFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEscapeFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript unescape builtin function. - static let jsUnescapeFunction = ILType.function([.jsAnything] => .jsString) + public static let jsUnescapeFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript decodeURI builtin function. - static let jsDecodeURIFunction = ILType.function([.jsAnything] => .jsString) + public static let jsDecodeURIFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript decodeURIComponent builtin function. - static let jsDecodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) + public static let jsDecodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript encodeURI builtin function. - static let jsEncodeURIFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEncodeURIFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript encodeURIComponent builtin function. - static let jsEncodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEncodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript eval builtin function. - static let jsEvalFunction = ILType.function([.string] => .jsAnything) + public static let jsEvalFunction = ILType.function([.string] => .jsAnything) /// Type of the JavaScript parseInt builtin function. - static let jsParseIntFunction = ILType.function([.string] => .integer) + public static let jsParseIntFunction = ILType.function([.string] => .integer) /// Type of the JavaScript parseFloat builtin function. - static let jsParseFloatFunction = ILType.function([.string] => .float) + public static let jsParseFloatFunction = ILType.function([.string] => .float) /// Type of the JavaScript undefined value. - static let jsUndefined = ILType.undefined + public static let jsUndefined = ILType.undefined /// Type of the JavaScript NaN value. - static let jsNaN = ILType.float + public static let jsNaN = ILType.float /// Type of the JavaScript Infinity value. - static let jsInfinity = ILType.float + public static let jsInfinity = ILType.float - static let jsWebAssemblyModule = ILType.object(ofGroup: "WebAssembly.Module") + public static let jsWebAssemblyModule = ILType.object(ofGroup: "WebAssembly.Module") /// Type of the WebAssembly.Module() constructor. // TODO: The first constructor argument can also be any typed array and .jsSharedArrayBuffer. - static let jsWebAssemblyModuleConstructor = + public static let jsWebAssemblyModuleConstructor = ILType.constructor([.plain(.jsArrayBuffer)] => .jsWebAssemblyModule) - + .object(ofGroup: "WebAssemblyModuleConstructor", withProperties: ["prototype"], + + .object( + ofGroup: "WebAssemblyModuleConstructor", withProperties: ["prototype"], withMethods: ["customSections", "imports", "exports"]) - static let jsWebAssemblyGlobalConstructor = + public static let jsWebAssemblyGlobalConstructor = // We do not type the result as being part of the ObjectGroup "WasmGlobal" as that would // require to also add a WasmTypeExtension to its type. This is fine as the proper // construction of globals is done via the high-level Wasm operations and these builtins // only serve the purpose of fuzzing the API. - ILType.constructor([.plain(.object()), .jsAnything] => .object(withProperties: ["value"], withMethods: ["valueOf"])) - + .object(ofGroup: "WebAssemblyGlobalConstructor", withProperties: ["prototype"], withMethods: []) - - static let jsWebAssemblyInstance = ILType.object(ofGroup: "WebAssembly.Instance", + ILType.constructor( + [.plain(.object()), .jsAnything] + => .object(withProperties: ["value"], withMethods: ["valueOf"])) + + .object( + ofGroup: "WebAssemblyGlobalConstructor", withProperties: ["prototype"], withMethods: []) + + public static let jsWebAssemblyInstance = ILType.object( + ofGroup: "WebAssembly.Instance", withProperties: ["exports"]) - static let jsWebAssemblyInstanceConstructor = - ILType.constructor([.plain(.jsWebAssemblyModule), .plain(.object())] => .jsWebAssemblyInstance) - + .object(ofGroup: "WebAssemblyInstanceConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsWebAssemblyInstanceConstructor = + ILType.constructor( + [.plain(.jsWebAssemblyModule), .plain(.object())] => .jsWebAssemblyInstance) + + .object( + ofGroup: "WebAssemblyInstanceConstructor", withProperties: ["prototype"], + withMethods: []) // Similarly to Wasm globals, we do not type the results as being part of an object group as the // result type doesn't have a valid WasmTypeExtension. - static let jsWebAssemblyMemoryConstructor = ILType.constructor([.plain(.object(withProperties: ["initial"]))] => .object(withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"])) + public static let jsWebAssemblyMemoryConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["initial"]))] + => .object( + withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"])) + .object(ofGroup: "WebAssemblyMemoryConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyTableConstructor = ILType.constructor([.plain(.object(withProperties: ["initial"]))] => object(withProperties: ["length"], withMethods: ["get", "grow", "set"])) + public static let jsWebAssemblyTableConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["initial"]))] + => object(withProperties: ["length"], withMethods: ["get", "grow", "set"])) + .object(ofGroup: "WebAssemblyTableConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyTagConstructor = ILType.constructor([.plain(.object(withProperties: ["parameters"]))] => object(withMethods: [])) + public static let jsWebAssemblyTagConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["parameters"]))] => object(withMethods: [])) + .object(ofGroup: "WebAssemblyTagConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyExceptionConstructor = ILType.constructor([.plain(ObjectGroup.jsWasmTag.instanceType), .plain(.jsArray), .opt(.object(withProperties: ["traceStack"]))] => ObjectGroup.jsWebAssemblyException.instanceType) + public static let jsWebAssemblyExceptionConstructor = + ILType.constructor( + [ + .plain(ObjectGroup.jsWasmTag.instanceType), .plain(.jsArray), + .opt(.object(withProperties: ["traceStack"])), + ] => ObjectGroup.jsWebAssemblyException.instanceType) + .object(ofGroup: "WebAssemblyExceptionConstructor", withProperties: ["prototype"]) // The JavaScript WebAssembly.Table object of the given variant, i.e. FuncRef or ExternRef - static let wasmTable = ILType.object(ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"]) + public static let wasmTable = ILType.object( + ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"]) // Temporal types - static let jsTemporalObject = ILType.object(ofGroup: "Temporal", withProperties: ["Instant", "Duration", "PlainTime", "PlainYearMonth", "PlainMonthDay", "PlainDate", "PlainDateTime", "ZonedDateTime", "Now"]) + public static let jsTemporalObject = ILType.object( + ofGroup: "Temporal", + withProperties: [ + "Instant", "Duration", "PlainTime", "PlainYearMonth", "PlainMonthDay", "PlainDate", + "PlainDateTime", "ZonedDateTime", "Now", + ]) // TODO(mliedtke): Can we stop documenting Object.prototype methods? It doesn't make much sense that half of the ObjectGroups register a toString method, // the other half doesn't and not a single one registers e.g. propertyIsEnumerable or isPrototypeOf.`? @@ -1388,50 +1755,155 @@ public extension ILType { // Note that Temporal toString accepts additional parameters private static let commonStringifierMethods = ["toString", "toJSON", "toLocaleString"] - static let jsTemporalInstant = ILType.object(ofGroup: "Temporal.Instant", withProperties: ["epochMilliseconds", "epochNanoseconds"], withMethods: ["add", "subtract", "until", "since", "round", "equals", "toZonedDateTimeISO"] + commonStringifierMethods) - - static let jsTemporalInstantConstructor = ILType.functionAndConstructor([.bigint] => .jsTemporalInstant) + .object(ofGroup: "TemporalInstantConstructor", withProperties: ["prototype"], withMethods: ["from", "fromEpochMilliseconds", "fromEpochNanoseconds", "compare"]) - - static let jsTemporalDuration = ILType.object(ofGroup: "Temporal.Duration", withProperties: ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "sign", "blank"], withMethods: ["with", "negated", "abs", "add", "subtract", "round", "total"] + commonStringifierMethods) - - static let jsTemporalDurationConstructor = ILType.functionAndConstructor([.opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .jsTemporalDuration) + .object(ofGroup: "TemporalDurationConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - fileprivate static let timeProperties = ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"] - static let jsTemporalPlainTime = ILType.object(ofGroup: "Temporal.PlainTime", withProperties: timeProperties, withMethods: ["add", "subtract", "with", "until", "since", "round", "equals"] + commonStringifierMethods) - - static let jsTemporalPlainTimeConstructor = ILType.functionAndConstructor([.opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .jsTemporalPlainTime) + .object(ofGroup: "TemporalPlainTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - static let jsTemporalCalendarEnum = ILType.enumeration(ofName: "temporalCalendar", withValues: ["buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", "islamicc", "iso8601", "japanese", "persian", "roc"]) - - fileprivate static let yearMonthProperties = ["calendarId", "era", "eraYear", "year", "month", "monthCode", "daysInMonth", "daysInYear", "monthsInYear", "inLeapYear"] - - static let jsTemporalPlainYearMonth = ILType.object(ofGroup: "Temporal.PlainYearMonth", withProperties: yearMonthProperties, withMethods: ["with", "add", "subtract", "until", "since", "equals", "toPlainDate"] + commonStringifierMethods) - - static let jsTemporalPlainYearMonthConstructor = ILType.functionAndConstructor([.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] => .jsTemporalPlainYearMonth) + .object(ofGroup: "TemporalPlainYearMonthConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - static let jsTemporalPlainMonthDay = ILType.object(ofGroup: "Temporal.PlainMonthDay", withProperties: ["calendarId", "monthCode", "day"], withMethods: ["with", "equals", "toPlainDate"] + commonStringifierMethods) - - static let jsTemporalPlainMonthDayConstructor = ILType.functionAndConstructor([.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] => .jsTemporalPlainMonthDay) + .object(ofGroup: "TemporalPlainMonthDayConstructor", withProperties: ["prototype"], withMethods: ["from"]) - - fileprivate static let dateProperties = yearMonthProperties + ["day", "dayOfYear", "dayOfWeek", "weekOfYear", "yearOfWeek", "daysInWeek"] - - static let jsTemporalPlainDate = ILType.object(ofGroup: "Temporal.PlainDate", withProperties: dateProperties, withMethods: ["toPlainYearMonth", "toPlainMonthDay", "add", "subtract", "with", "withCalendar", "until", "since", "equals", "toPlainDateTime", "toZonedDateTime"] + commonStringifierMethods) - - static let jsTemporalPlainDateConstructor = ILType.functionAndConstructor([.number, .number, .number, .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate) + .object(ofGroup: "TemporalPlainDateConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - - static let jsTemporalPlainDateTime = ILType.object(ofGroup: "Temporal.PlainDateTime", withProperties: dateProperties + timeProperties, withMethods: ["with", "withPlainTime", "withCalendar", "add", "subtract", "until", "since", "round", "equals", "toZonedDateTime", "toPlainDate", "toPlainTime"] + commonStringifierMethods) - - static let jsTemporalPlainDateTimeConstructor = ILType.functionAndConstructor([.number, .number, .number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDateTime) + .object(ofGroup: "TemporalPlainDateTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) + public static let jsTemporalInstant = ILType.object( + ofGroup: "Temporal.Instant", withProperties: ["epochMilliseconds", "epochNanoseconds"], + withMethods: ["add", "subtract", "until", "since", "round", "equals", "toZonedDateTimeISO"] + + commonStringifierMethods) + + public static let jsTemporalInstantConstructor = + ILType.functionAndConstructor([.bigint] => .jsTemporalInstant) + + .object( + ofGroup: "TemporalInstantConstructor", withProperties: ["prototype"], + withMethods: ["from", "fromEpochMilliseconds", "fromEpochNanoseconds", "compare"]) + + public static let jsTemporalDuration = ILType.object( + ofGroup: "Temporal.Duration", + withProperties: [ + "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", + "microseconds", "nanoseconds", "sign", "blank", + ], + withMethods: ["with", "negated", "abs", "add", "subtract", "round", "total"] + + commonStringifierMethods) + + public static let jsTemporalDurationConstructor = + ILType.functionAndConstructor( + [ + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + ] => .jsTemporalDuration) + + .object( + ofGroup: "TemporalDurationConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + fileprivate static let timeProperties = [ + "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", + ] + public static let jsTemporalPlainTime = ILType.object( + ofGroup: "Temporal.PlainTime", withProperties: timeProperties, + withMethods: ["add", "subtract", "with", "until", "since", "round", "equals"] + + commonStringifierMethods) + + public static let jsTemporalPlainTimeConstructor = + ILType.functionAndConstructor( + [ + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), + ] => .jsTemporalPlainTime) + + .object( + ofGroup: "TemporalPlainTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalCalendarEnum = ILType.enumeration( + ofName: "temporalCalendar", + withValues: [ + "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", + "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", + "islamicc", "iso8601", "japanese", "persian", "roc", + ]) - static let jsTemporalZonedDateTime = ILType.object(ofGroup: "Temporal.ZonedDateTime", withProperties: dateProperties + timeProperties + ["timeZoneId", "epochMilliseconds", "epochNanoseconds", "offsetNanoseconds", "offset"], withMethods: ["with", "withPlainTime", "withTimeZone", "withCalendar", "add", "subtract", "until", "since", "round", "equals", "startOfDay", "getTimeZoneTransition", "toInstant", "toPlainDate", "toPlainTime", "toPlainDateTime"] + commonStringifierMethods) + fileprivate static let yearMonthProperties = [ + "calendarId", "era", "eraYear", "year", "month", "monthCode", "daysInMonth", "daysInYear", + "monthsInYear", "inLeapYear", + ] - static let jsTemporalZonedDateTimeConstructor = ILType.functionAndConstructor([.bigint, .string, .opt(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime) + .object(ofGroup: "TemporalZonedDateTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) + public static let jsTemporalPlainYearMonth = ILType.object( + ofGroup: "Temporal.PlainYearMonth", withProperties: yearMonthProperties, + withMethods: ["with", "add", "subtract", "until", "since", "equals", "toPlainDate"] + + commonStringifierMethods) + + public static let jsTemporalPlainYearMonthConstructor = + ILType.functionAndConstructor( + [.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] + => .jsTemporalPlainYearMonth) + + .object( + ofGroup: "TemporalPlainYearMonthConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalPlainMonthDay = ILType.object( + ofGroup: "Temporal.PlainMonthDay", withProperties: ["calendarId", "monthCode", "day"], + withMethods: ["with", "equals", "toPlainDate"] + commonStringifierMethods) + + public static let jsTemporalPlainMonthDayConstructor = + ILType.functionAndConstructor( + [.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] + => .jsTemporalPlainMonthDay) + + .object( + ofGroup: "TemporalPlainMonthDayConstructor", withProperties: ["prototype"], + withMethods: ["from"]) + + fileprivate static let dateProperties = + yearMonthProperties + [ + "day", "dayOfYear", "dayOfWeek", "weekOfYear", "yearOfWeek", "daysInWeek", + ] - static let jsTemporalNow = ILType.object(ofGroup: "Temporal.Now", withProperties: [], withMethods: ["timeZoneId", "instant", "plainDateTimeISO", "zonedDateTimeISO", "plainDateISO", "plainTimeISO"]) + public static let jsTemporalPlainDate = ILType.object( + ofGroup: "Temporal.PlainDate", withProperties: dateProperties, + withMethods: [ + "toPlainYearMonth", "toPlainMonthDay", "add", "subtract", "with", "withCalendar", + "until", "since", "equals", "toPlainDateTime", "toZonedDateTime", + ] + commonStringifierMethods) + + public static let jsTemporalPlainDateConstructor = + ILType.functionAndConstructor( + [.number, .number, .number, .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate) + + .object( + ofGroup: "TemporalPlainDateConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalPlainDateTime = ILType.object( + ofGroup: "Temporal.PlainDateTime", withProperties: dateProperties + timeProperties, + withMethods: [ + "with", "withPlainTime", "withCalendar", "add", "subtract", "until", "since", "round", + "equals", "toZonedDateTime", "toPlainDate", "toPlainTime", + ] + commonStringifierMethods) + + public static let jsTemporalPlainDateTimeConstructor = + ILType.functionAndConstructor( + [ + .number, .number, .number, .opt(.number), .opt(.number), .opt(.number), + .opt(.number), .opt(.number), .opt(.number), .opt(.jsTemporalCalendarEnum), + ] => .jsTemporalPlainDateTime) + + .object( + ofGroup: "TemporalPlainDateTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalZonedDateTime = ILType.object( + ofGroup: "Temporal.ZonedDateTime", + withProperties: dateProperties + timeProperties + [ + "timeZoneId", "epochMilliseconds", "epochNanoseconds", "offsetNanoseconds", "offset", + ], + withMethods: [ + "with", "withPlainTime", "withTimeZone", "withCalendar", "add", "subtract", "until", + "since", "round", "equals", "startOfDay", "getTimeZoneTransition", "toInstant", + "toPlainDate", "toPlainTime", "toPlainDateTime", + ] + commonStringifierMethods) + + public static let jsTemporalZonedDateTimeConstructor = + ILType.functionAndConstructor( + [.bigint, .string, .opt(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime) + + .object( + ofGroup: "TemporalZonedDateTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalNow = ILType.object( + ofGroup: "Temporal.Now", withProperties: [], + withMethods: [ + "timeZoneId", "instant", "plainDateTimeISO", "zonedDateTimeISO", "plainDateISO", + "plainTimeISO", + ]) } -public extension ObjectGroup { +extension ObjectGroup { // Creates an object group representing a "prototype" object on a built-in, like Date.prototype. // These objects are somewhat special in JavaScript as they describe an object which has // methods on them for which you shall not call them with the bound this as a receiver, e.g. @@ -1440,14 +1912,17 @@ public extension ObjectGroup { // them. Instead Fuzzilli generates GetProperty operations for them which will then be typed as // an `ILType.unboundFunction` which knows the required receiver type (in the example `Date`), // so Fuzzilli can generate sequences like `Date.prototype.getTime.call(new Date())`. - static func createPrototypeObjectGroup( - _ receiver: ObjectGroup, - constructor: ILType = .object(), - excludeProperties: [String] = [], - additionalProperties: [String: ILType] = [:]) -> ObjectGroup { + public static func createPrototypeObjectGroup( + _ receiver: ObjectGroup, + constructor: ILType = .object(), + excludeProperties: [String] = [], + additionalProperties: [String: ILType] = [:] + ) -> ObjectGroup { let name = receiver.name + ".prototype" - var properties = Dictionary(uniqueKeysWithValues: receiver.methods.map { - ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) }) + var properties = Dictionary( + uniqueKeysWithValues: receiver.methods.map { + ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) + }) properties.merge(additionalProperties) { _, _ in fatalError("duplicate property") @@ -1467,7 +1942,8 @@ public extension ObjectGroup { } return ObjectGroup( name: name, - instanceType: .object(ofGroup: name, withProperties: properties.map {$0.0}, withMethods: []), + instanceType: .object( + ofGroup: name, withProperties: properties.map { $0.0 }, withMethods: []), properties: properties, methods: [:] ) @@ -1478,179 +1954,180 @@ public extension ObjectGroup { // The general rules here are: // * "output" type information (properties and return values) should be as precise as possible // * "input" type information (function parameters) should be as broad as possible -public extension ObjectGroup { +extension ObjectGroup { /// Object group modelling JavaScript strings - static let jsStrings = ObjectGroup( + public static let jsStrings = ObjectGroup( name: "String", instanceType: .jsString, properties: [ - "length" : .integer, + "length": .integer ], methods: [ - "charAt" : [.integer] => .jsString, - "charCodeAt" : [.integer] => .integer, - "codePointAt" : [.integer] => .integer, - "concat" : [.jsAnything...] => .jsString, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "endsWith" : [.string, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "match" : [.regexp] => .jsArray, - "matchAll" : [.regexp] => .jsIterator, - "normalize" : [] => .jsString, // the first parameter must be a specific string value, so we have a CodeGenerator for that instead - "padEnd" : [.integer, .opt(.string)] => .jsString, - "padStart" : [.integer, .opt(.string)] => .jsString, - "repeat" : [.integer] => .jsString, - "replace" : [.oneof(.string, .regexp), .string] => .jsString, - "replaceAll" : [.string, .string] => .jsString, - "search" : [.regexp] => .integer, - "slice" : [.integer, .opt(.integer)] => .jsString, - "split" : [.opt(.string), .opt(.integer)] => .jsArray, - "startsWith" : [.string, .opt(.integer)] => .boolean, - "substring" : [.integer, .opt(.integer)] => .jsString, - "trim" : [] => .undefined, - "trimStart" : [] => .jsString, - "trimLeft" : [] => .jsString, - "trimEnd" : [] => .jsString, - "trimRight" : [] => .jsString, - "toLowerCase" : [] => .jsString, - "toUpperCase" : [] => .jsString, - "localeCompare" : [.string, .opt(.string), .opt(.object())] => .integer, - "anchor" : [.string] => .jsString, - "at" : [.integer] => .jsString, - "big" : [] => .jsString, - "blink" : [] => .jsString, - "bold" : [] => .jsString, - "fixed" : [] => .jsString, - "fontcolor" : [.string] => .jsString, - "fontsize" : [.integer] => .jsString, + "charAt": [.integer] => .jsString, + "charCodeAt": [.integer] => .integer, + "codePointAt": [.integer] => .integer, + "concat": [.jsAnything...] => .jsString, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "endsWith": [.string, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "match": [.regexp] => .jsArray, + "matchAll": [.regexp] => .jsIterator, + "normalize": [] => .jsString, // the first parameter must be a specific string value, so we have a CodeGenerator for that instead + "padEnd": [.integer, .opt(.string)] => .jsString, + "padStart": [.integer, .opt(.string)] => .jsString, + "repeat": [.integer] => .jsString, + "replace": [.oneof(.string, .regexp), .string] => .jsString, + "replaceAll": [.string, .string] => .jsString, + "search": [.regexp] => .integer, + "slice": [.integer, .opt(.integer)] => .jsString, + "split": [.opt(.string), .opt(.integer)] => .jsArray, + "startsWith": [.string, .opt(.integer)] => .boolean, + "substring": [.integer, .opt(.integer)] => .jsString, + "trim": [] => .undefined, + "trimStart": [] => .jsString, + "trimLeft": [] => .jsString, + "trimEnd": [] => .jsString, + "trimRight": [] => .jsString, + "toLowerCase": [] => .jsString, + "toUpperCase": [] => .jsString, + "localeCompare": [.string, .opt(.string), .opt(.object())] => .integer, + "anchor": [.string] => .jsString, + "at": [.integer] => .jsString, + "big": [] => .jsString, + "blink": [] => .jsString, + "bold": [] => .jsString, + "fixed": [] => .jsString, + "fontcolor": [.string] => .jsString, + "fontsize": [.integer] => .jsString, "isWellFormed": [] => .boolean, - "italics" : [] => .jsString, - "link" : [.string] => .jsString, - "small" : [] => .jsString, - "strike" : [] => .jsString, - "sub" : [] => .jsString, - "substr" : [.integer, .opt(.integer)] => .jsString, - "sup" : [] => .jsString, - "toLocaleLowerCase" : [.opt(.jsIntlLocaleLike)] => .jsString, - "toLocaleUpperCase" : [.opt(.jsIntlLocaleLike)] => .jsString, + "italics": [] => .jsString, + "link": [.string] => .jsString, + "small": [] => .jsString, + "strike": [] => .jsString, + "sub": [] => .jsString, + "substr": [.integer, .opt(.integer)] => .jsString, + "sup": [] => .jsString, + "toLocaleLowerCase": [.opt(.jsIntlLocaleLike)] => .jsString, + "toLocaleUpperCase": [.opt(.jsIntlLocaleLike)] => .jsString, "toWellFormed": [] => .jsString, ] ) /// Object group modelling JavaScript regular expressions. - static let jsRegExps = ObjectGroup( + public static let jsRegExps = ObjectGroup( name: "RegExp", instanceType: .jsRegExp, properties: [ - "flags" : .string, - "dotAll" : .boolean, - "global" : .boolean, - "ignoreCase" : .boolean, - "multiline" : .boolean, - "source" : .string, - "sticky" : .boolean, - "unicode" : .boolean, + "flags": .string, + "dotAll": .boolean, + "global": .boolean, + "ignoreCase": .boolean, + "multiline": .boolean, + "source": .string, + "sticky": .boolean, + "unicode": .boolean, ], methods: [ - "compile" : [.string] => .jsRegExp, - "exec" : [.string] => .jsArray, - "test" : [.string] => .boolean, + "compile": [.string] => .jsRegExp, + "exec": [.string] => .jsArray, + "test": [.string] => .boolean, ] ) /// Object group modelling JavaScript arrays - static let jsArrays = ObjectGroup( + public static let jsArrays = ObjectGroup( name: "Array", instanceType: .jsArray, properties: [ - "length" : .integer, + "length": .integer ], methods: [ - "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsArray, - "entries" : [] => .jsIterator, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsArray, - "find" : [.function(), .opt(.object())] => .jsAnything, - "findIndex" : [.function(), .opt(.object())] => .integer, - "findLast" : [.function(), .opt(.object())] => .jsAnything, - "findLastIndex" : [.function(), .opt(.object())] => .integer, - "forEach" : [.function(), .opt(.object())] => .undefined, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "join" : [.string] => .jsString, - "keys" : [] => .jsIterator, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .jsArray, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .jsArray, - "values" : [] => .jsIterator, - "pop" : [] => .jsAnything, - "push" : [.jsAnything...] => .integer, - "shift" : [] => .jsAnything, - "splice" : [.integer, .opt(.integer), .jsAnything...] => .jsArray, - "unshift" : [.jsAnything...] => .integer, - "concat" : [.jsAnything...] => .jsArray, - "filter" : [.function(), .opt(.object())] => .jsArray, - "map" : [.function(), .opt(.object())] => .jsArray, - "slice" : [.opt(.integer), .opt(.integer)] => .jsArray, - "flat" : [.opt(.integer)] => .jsArray, - "flatMap" : [.function(), .opt(.jsAnything)] => .jsArray, - "toString" : [] => .jsString, - "toLocaleString" : [.opt(.string), .opt(.object())] => .jsString, - "toReversed" : [] => .jsArray, - "toSorted" : [.opt(.function())] => .jsArray, - "toSpliced" : [.integer, .opt(.integer), .jsAnything...] => .jsArray, - "with" : [.integer, .jsAnything] => .jsArray, + "at": [.integer] => .jsAnything, + "copyWithin": [.integer, .integer, .opt(.integer)] => .jsArray, + "entries": [] => .jsIterator, + "every": [.function(), .opt(.object())] => .boolean, + "fill": [.jsAnything, .opt(.integer), .opt(.integer)] => .jsArray, + "find": [.function(), .opt(.object())] => .jsAnything, + "findIndex": [.function(), .opt(.object())] => .integer, + "findLast": [.function(), .opt(.object())] => .jsAnything, + "findLastIndex": [.function(), .opt(.object())] => .integer, + "forEach": [.function(), .opt(.object())] => .undefined, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "join": [.string] => .jsString, + "keys": [] => .jsIterator, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "reduceRight": [.function(), .opt(.jsAnything)] => .jsAnything, + "reverse": [] => .jsArray, + "some": [.function(), .opt(.jsAnything)] => .boolean, + "sort": [.function()] => .jsArray, + "values": [] => .jsIterator, + "pop": [] => .jsAnything, + "push": [.jsAnything...] => .integer, + "shift": [] => .jsAnything, + "splice": [.integer, .opt(.integer), .jsAnything...] => .jsArray, + "unshift": [.jsAnything...] => .integer, + "concat": [.jsAnything...] => .jsArray, + "filter": [.function(), .opt(.object())] => .jsArray, + "map": [.function(), .opt(.object())] => .jsArray, + "slice": [.opt(.integer), .opt(.integer)] => .jsArray, + "flat": [.opt(.integer)] => .jsArray, + "flatMap": [.function(), .opt(.jsAnything)] => .jsArray, + "toString": [] => .jsString, + "toLocaleString": [.opt(.string), .opt(.object())] => .jsString, + "toReversed": [] => .jsArray, + "toSorted": [.opt(.function())] => .jsArray, + "toSpliced": [.integer, .opt(.integer), .jsAnything...] => .jsArray, + "with": [.integer, .jsAnything] => .jsArray, ] ) /// ObjectGroup modelling JavaScript functions - static let jsFunctions = ObjectGroup( + public static let jsFunctions = ObjectGroup( name: "Function", instanceType: .jsFunction(), properties: [ - "prototype" : .object(), - "length" : .integer, - "arguments" : .jsArray, - "caller" : .jsFunction(), - "name" : .jsString, + "prototype": .object(), + "length": .integer, + "arguments": .jsArray, + "caller": .jsFunction(), + "name": .jsString, ], methods: [ - "apply" : [.object(), .object()] => .jsAnything, - "call" : [.object(), .jsAnything...] => .jsAnything, - "bind" : [.object(), .jsAnything...] => .jsAnything, + "apply": [.object(), .object()] => .jsAnything, + "call": [.object(), .jsAnything...] => .jsAnything, + "bind": [.object(), .jsAnything...] => .jsAnything, ] ) - static let jsFunctionPrototype = createPrototypeObjectGroup(jsFunctions, + public static let jsFunctionPrototype = createPrototypeObjectGroup( + jsFunctions, constructor: .jsFunctionConstructor) - static let jsFunctionConstructor = ObjectGroup( + public static let jsFunctionConstructor = ObjectGroup( name: "FunctionConstructor", constructorPath: "Function", instanceType: .jsFunctionConstructor, properties: [ - "prototype" : jsFunctionPrototype.instanceType, + "prototype": jsFunctionPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript Symbols - static let jsSymbols = ObjectGroup( + public static let jsSymbols = ObjectGroup( name: "Symbol", instanceType: .jsSymbol, properties: [ - "description" : .jsString, + "description": .jsString ], methods: [:] ) /// Object group modelling JavaScript arguments objects. - static let jsArguments = ObjectGroup( + public static let jsArguments = ObjectGroup( name: "Arguments", instanceType: .jsArguments, properties: [ @@ -1660,95 +2137,97 @@ public extension ObjectGroup { methods: [:] ) - static let jsIterator = ObjectGroup( + public static let jsIterator = ObjectGroup( name: "Iterator", instanceType: .jsIterator, properties: [ "done": .boolean, - "value": .jsAnything + "value": .jsAnything, ], methods: [ - "next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "return" : [.jsAnything] => .object(withProperties: ["done", "value"]), - "throw" : [.jsAnything] => .object(withProperties: ["done", "value"]), - "map" : [.function()] => .jsIterator, - "filter" : [.function()] => .jsIterator, - "take" : [.integer] => .jsIterator, - "drop" : [.integer] => .jsIterator, - "flatMap" : [.function()] => .jsIterator, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "toArray" : [] => .jsArray, - "forEach" : [.function()] => .undefined, - "some" : [.function()] => .boolean, - "every" : [.function()] => .boolean, - "find" : [.function()] => .jsAnything, + "next": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "return": [.jsAnything] => .object(withProperties: ["done", "value"]), + "throw": [.jsAnything] => .object(withProperties: ["done", "value"]), + "map": [.function()] => .jsIterator, + "filter": [.function()] => .jsIterator, + "take": [.integer] => .jsIterator, + "drop": [.integer] => .jsIterator, + "flatMap": [.function()] => .jsIterator, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "toArray": [] => .jsArray, + "forEach": [.function()] => .undefined, + "some": [.function()] => .boolean, + "every": [.function()] => .boolean, + "find": [.function()] => .jsAnything, ] ) // next, return and throw are part of the Iterator protocol, not Iterator.prototype. - static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator, + public static let jsIteratorPrototype = createPrototypeObjectGroup( + jsIterator, constructor: .jsIteratorConstructor, excludeProperties: ["next", "return", "throw"]) - static let jsIteratorConstructor = ObjectGroup( + public static let jsIteratorConstructor = ObjectGroup( name: "IteratorConstructor", instanceType: .jsIteratorConstructor, properties: [ - "prototype" : jsIteratorPrototype.instanceType + "prototype": jsIteratorPrototype.instanceType ], methods: [ - "from" : [.jsAnything] => .jsIterator, - "concat" : [.jsAnything...] => .jsIterator, - "zip" : [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] => .jsIterator, + "from": [.jsAnything] => .jsIterator, + "concat": [.jsAnything...] => .jsIterator, + "zip": [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] + => .jsIterator, ] ) - static let jsGenerators = ObjectGroup( + public static let jsGenerators = ObjectGroup( name: "Generator", instanceType: .jsGenerator, properties: [:], methods: [ - "next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "return" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "throw" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "next": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "return": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "throw": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), ] ) /// Object group modelling JavaScript promises. - static let jsPromises = ObjectGroup( + public static let jsPromises = ObjectGroup( name: "Promise", instanceType: .jsPromise, properties: [:], methods: [ - "catch" : [.function()] => .jsPromise, - "then" : [.function()] => .jsPromise, - "finally" : [.function()] => .jsPromise, + "catch": [.function()] => .jsPromise, + "then": [.function()] => .jsPromise, + "finally": [.function()] => .jsPromise, ] ) /// ObjectGroup modelling JavaScript Map objects - static let jsMaps = ObjectGroup( + public static let jsMaps = ObjectGroup( name: "Map", instanceType: .jsMap, properties: [ - "size" : .integer + "size": .integer ], methods: [ - "clear" : [] => .undefined, - "delete" : [.jsAnything] => .boolean, - "entries" : [] => .jsIterator, - "forEach" : [.function(), .opt(.object())] => .undefined, - "get" : [.jsAnything] => .jsAnything, - "has" : [.jsAnything] => .boolean, - "keys" : [] => .jsIterator, - "set" : [.jsAnything, .jsAnything] => .jsMap, - "values" : [] => .jsIterator, - "getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything, + "clear": [] => .undefined, + "delete": [.jsAnything] => .boolean, + "entries": [] => .jsIterator, + "forEach": [.function(), .opt(.object())] => .undefined, + "get": [.jsAnything] => .jsAnything, + "has": [.jsAnything] => .boolean, + "keys": [] => .jsIterator, + "set": [.jsAnything, .jsAnything] => .jsMap, + "values": [] => .jsIterator, + "getOrInsert": [.jsAnything, .jsAnything] => .jsAnything, "getOrInsertComputed": [.jsAnything, .function()] => .jsAnything, ] ) - static let jsProxyConstructor = ObjectGroup( + public static let jsProxyConstructor = ObjectGroup( name: "ProxyConstructor", constructorPath: "Proxy", instanceType: .jsProxyConstructor, @@ -1758,15 +2237,16 @@ public extension ObjectGroup { ] ) - static let jsMapPrototype = createPrototypeObjectGroup(jsMaps, + public static let jsMapPrototype = createPrototypeObjectGroup( + jsMaps, constructor: .jsMapConstructor) - static let jsMapConstructor = ObjectGroup( + public static let jsMapConstructor = ObjectGroup( name: "MapConstructor", constructorPath: "Map", instanceType: .jsMapConstructor, properties: [ - "prototype" : jsMapPrototype.instanceType + "prototype": jsMapPrototype.instanceType ], methods: [ "groupBy": [.iterable, .function()] => .jsMap @@ -1774,305 +2254,318 @@ public extension ObjectGroup { ) /// ObjectGroup modelling JavaScript WeakMap objects - static let jsWeakMaps = ObjectGroup( + public static let jsWeakMaps = ObjectGroup( name: "WeakMap", instanceType: .jsWeakMap, properties: [:], methods: [ - "delete" : [.jsAnything] => .boolean, - "get" : [.jsAnything] => .jsAnything, - "has" : [.jsAnything] => .boolean, - "set" : [.jsAnything, .jsAnything] => .jsWeakMap, - "getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything, + "delete": [.jsAnything] => .boolean, + "get": [.jsAnything] => .jsAnything, + "has": [.jsAnything] => .boolean, + "set": [.jsAnything, .jsAnything] => .jsWeakMap, + "getOrInsert": [.jsAnything, .jsAnything] => .jsAnything, "getOrInsertComputed": [.jsAnything, .function()] => .jsAnything, ] ) - static let jsWeakMapPrototype = createPrototypeObjectGroup(jsWeakMaps, + public static let jsWeakMapPrototype = createPrototypeObjectGroup( + jsWeakMaps, constructor: .jsWeakMapConstructor) - static let jsWeakMapConstructor = ObjectGroup( + public static let jsWeakMapConstructor = ObjectGroup( name: "WeakMapConstructor", constructorPath: "WeakMap", instanceType: .jsWeakMapConstructor, properties: [ - "prototype" : jsWeakMapPrototype.instanceType + "prototype": jsWeakMapPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript Set objects - static let jsSets = ObjectGroup( + public static let jsSets = ObjectGroup( name: "Set", instanceType: .jsSet, properties: [ - "size" : .integer + "size": .integer ], methods: [ - "add" : [.jsAnything] => .jsSet, - "clear" : [] => .undefined, - "delete" : [.jsAnything] => .boolean, - "difference" : [.plain(.jsSet)] => .jsSet, - "entries" : [] => .jsIterator, - "forEach" : [.function(), .opt(.object())] => .undefined, - "has" : [.jsAnything] => .boolean, - "intersection" : [.plain(.jsSet)] => .jsSet, - "isDisjointFrom" : [.plain(.jsSet)] => .boolean, - "isSubsetOf" : [.plain(.jsSet)] => .boolean, - "isSupersetOf" : [.plain(.jsSet)] => .boolean, - "keys" : [] => .jsIterator, - "symmetricDifference" : [.plain(.jsSet)] => .jsSet, - "union" : [.plain(.jsSet)] => .jsSet, - "values" : [] => .jsIterator, + "add": [.jsAnything] => .jsSet, + "clear": [] => .undefined, + "delete": [.jsAnything] => .boolean, + "difference": [.plain(.jsSet)] => .jsSet, + "entries": [] => .jsIterator, + "forEach": [.function(), .opt(.object())] => .undefined, + "has": [.jsAnything] => .boolean, + "intersection": [.plain(.jsSet)] => .jsSet, + "isDisjointFrom": [.plain(.jsSet)] => .boolean, + "isSubsetOf": [.plain(.jsSet)] => .boolean, + "isSupersetOf": [.plain(.jsSet)] => .boolean, + "keys": [] => .jsIterator, + "symmetricDifference": [.plain(.jsSet)] => .jsSet, + "union": [.plain(.jsSet)] => .jsSet, + "values": [] => .jsIterator, ] ) - static let jsSetPrototype = createPrototypeObjectGroup(jsSets, + public static let jsSetPrototype = createPrototypeObjectGroup( + jsSets, constructor: .jsSetConstructor) - static let jsSetConstructor = ObjectGroup( + public static let jsSetConstructor = ObjectGroup( name: "SetConstructor", constructorPath: "Set", instanceType: .jsSetConstructor, properties: [ - "prototype" : jsSetPrototype.instanceType + "prototype": jsSetPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript WeakSet objects - static let jsWeakSets = ObjectGroup( + public static let jsWeakSets = ObjectGroup( name: "WeakSet", instanceType: .jsWeakSet, properties: [:], methods: [ - "add" : [.jsAnything] => .jsWeakSet, - "delete" : [.jsAnything] => .boolean, - "has" : [.jsAnything] => .boolean, + "add": [.jsAnything] => .jsWeakSet, + "delete": [.jsAnything] => .boolean, + "has": [.jsAnything] => .boolean, ] ) - static let jsWeakSetPrototype = createPrototypeObjectGroup(jsWeakSets, + public static let jsWeakSetPrototype = createPrototypeObjectGroup( + jsWeakSets, constructor: .jsWeakSetConstructor) - static let jsWeakSetConstructor = ObjectGroup( + public static let jsWeakSetConstructor = ObjectGroup( name: "WeakSetConstructor", constructorPath: "WeakSet", instanceType: .jsWeakSetConstructor, properties: [ - "prototype" : jsWeakSetPrototype.instanceType + "prototype": jsWeakSetPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript WeakRef objects - static let jsWeakRefs = ObjectGroup( + public static let jsWeakRefs = ObjectGroup( name: "WeakRef", instanceType: .jsWeakRef, properties: [:], methods: [ - "deref" : [] => .object(), + "deref": [] => .object() ] ) - static let jsWeakRefPrototype = createPrototypeObjectGroup(jsWeakRefs, + public static let jsWeakRefPrototype = createPrototypeObjectGroup( + jsWeakRefs, constructor: .jsWeakRefConstructor) - static let jsWeakRefConstructor = ObjectGroup( + public static let jsWeakRefConstructor = ObjectGroup( name: "WeakRefConstructor", constructorPath: "WeakRef", instanceType: .jsWeakRefConstructor, properties: [ - "prototype" : jsWeakRefPrototype.instanceType + "prototype": jsWeakRefPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript FinalizationRegistry objects - static let jsFinalizationRegistrys = ObjectGroup( + public static let jsFinalizationRegistrys = ObjectGroup( name: "FinalizationRegistry", instanceType: .jsFinalizationRegistry, properties: [:], methods: [ - "register" : [.object(), .jsAnything, .opt(.object())] => .undefined, - "unregister" : [.jsAnything] => .boolean, + "register": [.object(), .jsAnything, .opt(.object())] => .undefined, + "unregister": [.jsAnything] => .boolean, ] ) - static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup(jsFinalizationRegistrys, + public static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup( + jsFinalizationRegistrys, constructor: .jsFinalizationRegistryConstructor) - static let jsFinalizationRegistryConstructor = ObjectGroup( + public static let jsFinalizationRegistryConstructor = ObjectGroup( name: "FinalizationRegistryConstructor", constructorPath: "FinalizationRegistry", instanceType: .jsFinalizationRegistryConstructor, properties: [ - "prototype" : jsFinalizationRegistryPrototype.instanceType + "prototype": jsFinalizationRegistryPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript DisposableStack objects - static let jsDisposableStacks = ObjectGroup( + public static let jsDisposableStacks = ObjectGroup( name: "DisposableStack", instanceType: .jsDisposableStack, properties: [ - "disposed" : .boolean + "disposed": .boolean ], methods: [ - "dispose" : [] => .undefined, - "use" : [.jsAnything] => .jsAnything, - "adopt" : [.jsAnything, .function()] => .jsAnything, - "defer" : [.function()] => .undefined, - "move" : [] => .jsDisposableStack, + "dispose": [] => .undefined, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsDisposableStack, ] ) - static let jsDisposableStackPrototype = createPrototypeObjectGroup(jsDisposableStacks, + public static let jsDisposableStackPrototype = createPrototypeObjectGroup( + jsDisposableStacks, constructor: .jsDisposableStackConstructor) - static let jsDisposableStackConstructor = ObjectGroup( + public static let jsDisposableStackConstructor = ObjectGroup( name: "DisposableStackConstructor", constructorPath: "DisposableStack", instanceType: .jsDisposableStackConstructor, properties: [ - "prototype" : jsDisposableStackPrototype.instanceType + "prototype": jsDisposableStackPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript AsyncDisposableStack objects - static let jsAsyncDisposableStacks = ObjectGroup( + public static let jsAsyncDisposableStacks = ObjectGroup( name: "AsyncDisposableStack", instanceType: .jsAsyncDisposableStack, properties: [ - "disposed" : .boolean + "disposed": .boolean ], methods: [ - "disposeAsync" : [] => .jsPromise, - "use" : [.jsAnything] => .jsAnything, - "adopt" : [.jsAnything, .function()] => .jsAnything, - "defer" : [.function()] => .undefined, - "move" : [] => .jsAsyncDisposableStack, + "disposeAsync": [] => .jsPromise, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsAsyncDisposableStack, ] ) - static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup(jsAsyncDisposableStacks, + public static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup( + jsAsyncDisposableStacks, constructor: .jsAsyncDisposableStackConstructor) - static let jsAsyncDisposableStackConstructor = ObjectGroup( + public static let jsAsyncDisposableStackConstructor = ObjectGroup( name: "AsyncDisposableStackConstructor", constructorPath: "AsyncDisposableStack", instanceType: .jsAsyncDisposableStackConstructor, properties: [ - "prototype" : jsAsyncDisposableStackPrototype.instanceType + "prototype": jsAsyncDisposableStackPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript ArrayBuffer objects - static let jsArrayBuffers = ObjectGroup( + public static let jsArrayBuffers = ObjectGroup( name: "ArrayBuffer", instanceType: .jsArrayBuffer, properties: [ - "byteLength" : .integer, - "maxByteLength" : .integer, - "resizable" : .boolean, + "byteLength": .integer, + "maxByteLength": .integer, + "resizable": .boolean, ], methods: [ - "resize" : [.integer] => .undefined, - "slice" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, - "sliceToImmutable" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, - "transfer" : [.opt(.integer)] => .jsArrayBuffer, - "transferToFixedLength" : [.opt(.integer)] => .jsArrayBuffer, - "transferToImmutable" : [.opt(.integer)] => .jsArrayBuffer, + "resize": [.integer] => .undefined, + "slice": [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, + "sliceToImmutable": [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, + "transfer": [.opt(.integer)] => .jsArrayBuffer, + "transferToFixedLength": [.opt(.integer)] => .jsArrayBuffer, + "transferToImmutable": [.opt(.integer)] => .jsArrayBuffer, ] ) /// ObjectGroup modelling JavaScript SharedArrayBuffer objects - static let jsSharedArrayBuffers = ObjectGroup( + public static let jsSharedArrayBuffers = ObjectGroup( name: "SharedArrayBuffer", instanceType: .jsSharedArrayBuffer, properties: [ - "byteLength" : .integer, - "maxByteLength" : .integer, - "growable" : .boolean, + "byteLength": .integer, + "maxByteLength": .integer, + "growable": .boolean, ], methods: [ - "grow" : [.number] => .undefined, - "slice" : [.integer, .opt(.integer)] => .jsSharedArrayBuffer, + "grow": [.number] => .undefined, + "slice": [.integer, .opt(.integer)] => .jsSharedArrayBuffer, ] ) /// ObjectGroup modelling JavaScript TypedArray objects - static func jsTypedArrays(_ variant: String) -> ObjectGroup { + public static func jsTypedArrays(_ variant: String) -> ObjectGroup { // Extra methods from the base64 proposal: https://tc39.es/proposal-arraybuffer-base64/ - let extraMethods: [String: Signature] = variant != "Uint8Array" ? [:] : [ - "toBase64": [.opt(OptionsBag.toBase64Settings.group.instanceType)] => .string, - "toHex": [] => .string, - "setFromBase64": [.string, .opt(OptionsBag.fromBase64Settings.group.instanceType)] - => .object(withProperties: ["read", "written"]), - "setFromHex": [.string] => .object(withProperties: ["read", "written"]), - ] + let extraMethods: [String: Signature] = + variant != "Uint8Array" + ? [:] + : [ + "toBase64": [.opt(OptionsBag.toBase64Settings.group.instanceType)] => .string, + "toHex": [] => .string, + "setFromBase64": [.string, .opt(OptionsBag.fromBase64Settings.group.instanceType)] + => .object(withProperties: ["read", "written"]), + "setFromHex": [.string] => .object(withProperties: ["read", "written"]), + ] return ObjectGroup( name: variant, instanceType: .jsTypedArray(variant), properties: [ "BYTES_PER_ELEMENT": .integer, - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer, - "length" : .integer + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, + "length": .integer, ], methods: [ - "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsTypedArray(variant), - "entries" : [] => .jsIterator, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "find" : [.function(), .opt(.object())] => .jsAnything, - "findIndex" : [.function(), .opt(.object())] => .integer, - "findLast" : [.function(), .opt(.object())] => .jsAnything, - "findLastIndex" : [.function(), .opt(.object())] => .integer, - "forEach" : [.function(), .opt(.object())] => .undefined, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "join" : [.string] => .jsString, - "keys" : [] => .jsIterator, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .jsTypedArray(variant), - "set" : [.object(), .opt(.integer)] => .undefined, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .jsTypedArray(variant), - "values" : [] => .jsIterator, - "filter" : [.function(), .opt(.object())] => .jsTypedArray(variant), - "map" : [.function(), .opt(.object())] => .jsTypedArray(variant), - "slice" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "subarray" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "toString" : [] => .jsString, - "toLocaleString" : [.opt(.string), .opt(.object())] => .jsString, - "toReversed" : [] => .jsTypedArray(variant), - "toSorted" : [.opt(.function())] => .jsTypedArray(variant), - "with" : [.integer, .jsAnything] => .jsTypedArray(variant), + "at": [.integer] => .jsAnything, + "copyWithin": [.integer, .integer, .opt(.integer)] => .jsTypedArray(variant), + "entries": [] => .jsIterator, + "every": [.function(), .opt(.object())] => .boolean, + "fill": [.jsAnything, .opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "find": [.function(), .opt(.object())] => .jsAnything, + "findIndex": [.function(), .opt(.object())] => .integer, + "findLast": [.function(), .opt(.object())] => .jsAnything, + "findLastIndex": [.function(), .opt(.object())] => .integer, + "forEach": [.function(), .opt(.object())] => .undefined, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "join": [.string] => .jsString, + "keys": [] => .jsIterator, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "reduceRight": [.function(), .opt(.jsAnything)] => .jsAnything, + "reverse": [] => .jsTypedArray(variant), + "set": [.object(), .opt(.integer)] => .undefined, + "some": [.function(), .opt(.jsAnything)] => .boolean, + "sort": [.function()] => .jsTypedArray(variant), + "values": [] => .jsIterator, + "filter": [.function(), .opt(.object())] => .jsTypedArray(variant), + "map": [.function(), .opt(.object())] => .jsTypedArray(variant), + "slice": [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "subarray": [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "toString": [] => .jsString, + "toLocaleString": [.opt(.string), .opt(.object())] => .jsString, + "toReversed": [] => .jsTypedArray(variant), + "toSorted": [.opt(.function())] => .jsTypedArray(variant), + "with": [.integer, .jsAnything] => .jsTypedArray(variant), ].merging(extraMethods) { _, _ in fatalError("duplicate method") } ) } - static func jsTypedArrayPrototype(_ variant: String) -> ObjectGroup { + public static func jsTypedArrayPrototype(_ variant: String) -> ObjectGroup { return createPrototypeObjectGroup( jsTypedArrays(variant), constructor: .jsTypedArrayConstructor(variant), additionalProperties: [ - "BYTES_PER_ELEMENT": .integer, + "BYTES_PER_ELEMENT": .integer ]) } - static func jsTypedArrayConstructor(_ variant: String) -> ObjectGroup { - let methods : [String : Signature] = variant == "Uint8Array" + public static func jsTypedArrayConstructor(_ variant: String) -> ObjectGroup { + let methods: [String: Signature] = + variant == "Uint8Array" ? [ - "fromBase64": [.plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType)] => .jsUint8Array, + "fromBase64": [ + .plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType), + ] => .jsUint8Array, "fromHex": [.plain(.string)] => .jsUint8Array, ] : [:] @@ -2089,296 +2582,318 @@ public extension ObjectGroup { } /// ObjectGroup modelling JavaScript DataView objects - static let jsDataViews = ObjectGroup( + public static let jsDataViews = ObjectGroup( name: "DataView", instanceType: .jsDataView, properties: [ - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, ], methods: [ - "getInt8" : [.integer] => .integer, - "getUint8" : [.integer] => .integer, - "getInt16" : [.integer, .opt(.boolean)] => .integer, - "getUint16" : [.integer, .opt(.boolean)] => .integer, - "getInt32" : [.integer, .opt(.boolean)] => .integer, - "getUint32" : [.integer, .opt(.boolean)] => .integer, - "getFloat16" : [.integer, .opt(.boolean)] => .float, - "getFloat32" : [.integer, .opt(.boolean)] => .float, - "getFloat64" : [.integer, .opt(.boolean)] => .float, - "getBigInt64" : [.integer, .opt(.boolean)] => .bigint, + "getInt8": [.integer] => .integer, + "getUint8": [.integer] => .integer, + "getInt16": [.integer, .opt(.boolean)] => .integer, + "getUint16": [.integer, .opt(.boolean)] => .integer, + "getInt32": [.integer, .opt(.boolean)] => .integer, + "getUint32": [.integer, .opt(.boolean)] => .integer, + "getFloat16": [.integer, .opt(.boolean)] => .float, + "getFloat32": [.integer, .opt(.boolean)] => .float, + "getFloat64": [.integer, .opt(.boolean)] => .float, + "getBigInt64": [.integer, .opt(.boolean)] => .bigint, "getBigUint64": [.integer, .opt(.boolean)] => .bigint, - "setInt8" : [.integer, .integer] => .undefined, - "setUint8" : [.integer, .integer] => .undefined, - "setInt16" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setUint16" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setInt32" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setUint32" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setFloat16" : [.integer, .float, .opt(.boolean)] => .undefined, - "setFloat32" : [.integer, .float, .opt(.boolean)] => .undefined, - "setFloat64" : [.integer, .float, .opt(.boolean)] => .undefined, - "setBigInt64" : [.integer, .bigint, .opt(.boolean)] => .undefined, - "setBigUint64" : [.integer, .bigint, .opt(.boolean)] => .undefined, + "setInt8": [.integer, .integer] => .undefined, + "setUint8": [.integer, .integer] => .undefined, + "setInt16": [.integer, .integer, .opt(.boolean)] => .undefined, + "setUint16": [.integer, .integer, .opt(.boolean)] => .undefined, + "setInt32": [.integer, .integer, .opt(.boolean)] => .undefined, + "setUint32": [.integer, .integer, .opt(.boolean)] => .undefined, + "setFloat16": [.integer, .float, .opt(.boolean)] => .undefined, + "setFloat32": [.integer, .float, .opt(.boolean)] => .undefined, + "setFloat64": [.integer, .float, .opt(.boolean)] => .undefined, + "setBigInt64": [.integer, .bigint, .opt(.boolean)] => .undefined, + "setBigUint64": [.integer, .bigint, .opt(.boolean)] => .undefined, ] ) - static let jsDataViewPrototype = createPrototypeObjectGroup(jsDataViews, + public static let jsDataViewPrototype = createPrototypeObjectGroup( + jsDataViews, constructor: .jsDataViewConstructor) - static let jsDataViewConstructor = ObjectGroup( + public static let jsDataViewConstructor = ObjectGroup( name: "DataViewConstructor", constructorPath: "DataView", instanceType: .jsDataViewConstructor, properties: [ - "prototype": jsDataViewPrototype.instanceType, + "prototype": jsDataViewPrototype.instanceType ], methods: [:] ) - static let jsPromisePrototype = + public static let jsPromisePrototype = createPrototypeObjectGroup(jsPromises, constructor: .jsPromiseConstructor) /// ObjectGroup modelling the JavaScript Promise constructor builtin - static let jsPromiseConstructor = ObjectGroup( + public static let jsPromiseConstructor = ObjectGroup( name: "PromiseConstructor", constructorPath: "Promise", instanceType: .jsPromiseConstructor, properties: [ - "prototype" : jsPromisePrototype.instanceType + "prototype": jsPromisePrototype.instanceType ], methods: [ - "resolve" : [.jsAnything] => .jsPromise, - "reject" : [.jsAnything] => .jsPromise, - "all" : [.iterable] => .jsPromise, - "any" : [.iterable] => .jsPromise, - "race" : [.iterable] => .jsPromise, - "allSettled" : [.iterable] => .jsPromise, - "try" : [.function(), .jsAnything...] => .jsPromise, + "resolve": [.jsAnything] => .jsPromise, + "reject": [.jsAnything] => .jsPromise, + "all": [.iterable] => .jsPromise, + "any": [.iterable] => .jsPromise, + "race": [.iterable] => .jsPromise, + "allSettled": [.iterable] => .jsPromise, + "try": [.function(), .jsAnything...] => .jsPromise, "withResolvers": [] => .object(withProperties: ["promise", "resolve", "reject"]), ] ) /// ObjectGroup modelling JavaScript Date objects - static let jsDate = ObjectGroup( + public static let jsDate = ObjectGroup( name: "Date", instanceType: .jsDate, properties: [:], methods: [ - "toISOString" : [] => .jsString, - "toDateString" : [] => .jsString, - "toTimeString" : [] => .jsString, - "toLocaleString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "toLocaleDateString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "toLocaleTimeString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "getTime" : [] => .number, - "getFullYear" : [] => .number, - "getUTCFullYear" : [] => .number, - "getMonth" : [] => .number, - "getUTCMonth" : [] => .number, - "getDate" : [] => .number, - "getUTCDate" : [] => .number, - "getDay" : [] => .number, - "getUTCDay" : [] => .number, - "getHours" : [] => .number, - "getUTCHours" : [] => .number, - "getMinutes" : [] => .number, - "getUTCMinutes" : [] => .number, - "getSeconds" : [] => .number, - "getUTCSeconds" : [] => .number, - "getMilliseconds" : [] => .number, - "getUTCMilliseconds" : [] => .number, - "getTimezoneOffset" : [] => .number, - "getYear" : [] => .number, - "setTime" : [.number] => .number, - "setMilliseconds" : [.number] => .number, - "setUTCMilliseconds" : [.number] => .number, - "setSeconds" : [.number] => .number, - "setUTCSeconds" : [.number, .opt(.number)] => .number, - "setMinutes" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCMinutes" : [.number, .opt(.number), .opt(.number)] => .number, - "setHours" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCHours" : [.number, .opt(.number), .opt(.number)] => .number, - "setDate" : [.number] => .number, - "setUTCDate" : [.number] => .number, - "setMonth" : [.number] => .number, - "setUTCMonth" : [.number] => .number, - "setFullYear" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCFullYear" : [.number, .opt(.number), .opt(.number)] => .number, - "setYear" : [.number] => .number, - "toJSON" : [] => .jsString, - "toUTCString" : [] => .jsString, - "toGMTString" : [] => .jsString, - "toTemporalInstant" : [] => .jsTemporalInstant, + "toISOString": [] => .jsString, + "toDateString": [] => .jsString, + "toTimeString": [] => .jsString, + "toLocaleString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "toLocaleDateString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "toLocaleTimeString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "getTime": [] => .number, + "getFullYear": [] => .number, + "getUTCFullYear": [] => .number, + "getMonth": [] => .number, + "getUTCMonth": [] => .number, + "getDate": [] => .number, + "getUTCDate": [] => .number, + "getDay": [] => .number, + "getUTCDay": [] => .number, + "getHours": [] => .number, + "getUTCHours": [] => .number, + "getMinutes": [] => .number, + "getUTCMinutes": [] => .number, + "getSeconds": [] => .number, + "getUTCSeconds": [] => .number, + "getMilliseconds": [] => .number, + "getUTCMilliseconds": [] => .number, + "getTimezoneOffset": [] => .number, + "getYear": [] => .number, + "setTime": [.number] => .number, + "setMilliseconds": [.number] => .number, + "setUTCMilliseconds": [.number] => .number, + "setSeconds": [.number] => .number, + "setUTCSeconds": [.number, .opt(.number)] => .number, + "setMinutes": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCMinutes": [.number, .opt(.number), .opt(.number)] => .number, + "setHours": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCHours": [.number, .opt(.number), .opt(.number)] => .number, + "setDate": [.number] => .number, + "setUTCDate": [.number] => .number, + "setMonth": [.number] => .number, + "setUTCMonth": [.number] => .number, + "setFullYear": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCFullYear": [.number, .opt(.number), .opt(.number)] => .number, + "setYear": [.number] => .number, + "toJSON": [] => .jsString, + "toUTCString": [] => .jsString, + "toGMTString": [] => .jsString, + "toTemporalInstant": [] => .jsTemporalInstant, ] ) - static let jsDatePrototype = createPrototypeObjectGroup(jsDate, constructor: .jsDateConstructor) + public static let jsDatePrototype = createPrototypeObjectGroup( + jsDate, constructor: .jsDateConstructor) /// ObjectGroup modelling the JavaScript Date constructor - static let jsDateConstructor = ObjectGroup( + public static let jsDateConstructor = ObjectGroup( name: "DateConstructor", constructorPath: "Date", instanceType: .jsDateConstructor, properties: [ - "prototype" : jsDatePrototype.instanceType + "prototype": jsDatePrototype.instanceType ], methods: [ - "UTC" : [.number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .number, - "now" : [] => .number, - "parse" : [.string] => .number, + "UTC": [ + .number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), + ] => .number, + "now": [] => .number, + "parse": [.string] => .number, ] ) /// ObjectGroup modelling the JavaScript Object constructor builtin - static let jsObjectConstructor = ObjectGroup( + public static let jsObjectConstructor = ObjectGroup( name: "ObjectConstructor", constructorPath: "Object", instanceType: .jsObjectConstructor, properties: [ - "prototype" : .object(), // TODO + "prototype": .object() // TODO ], methods: [ - "assign" : [.object(), .object()] => .object(), - "create" : [.object(), .object()] => .object(), - "defineProperty" : [.object(), .string, .oneof(.object(withProperties: ["configurable", "writable", "enumerable", "value"]), .object(withMethods: ["get", "set"]))] => .object(), - "defineProperties" : [.object(), .object()] => .object(), - "entries" : [.object()] => .object(), - "freeze" : [.object()] => .object(), - "fromEntries" : [.object()] => .object(), - "getOwnPropertyDescriptor" : [.object(), .string] => .object(withProperties: ["configurable", "writable", "enumerable", "value"]), - "getOwnPropertyDescriptors" : [.object()] => .object(), - "getOwnPropertyNames" : [.object()] => .jsArray, - "getOwnPropertySymbols" : [.object()] => .jsArray, - "getPrototypeOf" : [.object()] => .object(), - "is" : [.object(), .object()] => .boolean, - "isExtensible" : [.object()] => .boolean, - "isFrozen" : [.object()] => .boolean, - "isSealed" : [.object()] => .boolean, - "keys" : [.object()] => .jsArray, - "preventExtensions" : [.object()] => .object(), - "seal" : [.object()] => .object(), - "setPrototypeOf" : [.object(), .object()] => .object(), - "values" : [.object()] => .jsArray, - "groupBy" : [.iterable, .function()] => .object(), - "hasOwn" : [.object(), .oneof(.jsString, .jsSymbol)] => .boolean, + "assign": [.object(), .object()] => .object(), + "create": [.object(), .object()] => .object(), + "defineProperty": [ + .object(), .string, + .oneof( + .object(withProperties: ["configurable", "writable", "enumerable", "value"]), + .object(withMethods: ["get", "set"])), + ] => .object(), + "defineProperties": [.object(), .object()] => .object(), + "entries": [.object()] => .object(), + "freeze": [.object()] => .object(), + "fromEntries": [.object()] => .object(), + "getOwnPropertyDescriptor": [.object(), .string] + => .object(withProperties: ["configurable", "writable", "enumerable", "value"]), + "getOwnPropertyDescriptors": [.object()] => .object(), + "getOwnPropertyNames": [.object()] => .jsArray, + "getOwnPropertySymbols": [.object()] => .jsArray, + "getPrototypeOf": [.object()] => .object(), + "is": [.object(), .object()] => .boolean, + "isExtensible": [.object()] => .boolean, + "isFrozen": [.object()] => .boolean, + "isSealed": [.object()] => .boolean, + "keys": [.object()] => .jsArray, + "preventExtensions": [.object()] => .object(), + "seal": [.object()] => .object(), + "setPrototypeOf": [.object(), .object()] => .object(), + "values": [.object()] => .jsArray, + "groupBy": [.iterable, .function()] => .object(), + "hasOwn": [.object(), .oneof(.jsString, .jsSymbol)] => .boolean, ] ) /// ObjectGroup modelling the JavaScript Array constructor builtin - static let jsArrayConstructor = ObjectGroup( + public static let jsArrayConstructor = ObjectGroup( name: "ArrayConstructor", constructorPath: "Array", instanceType: .jsArrayConstructor, properties: [ // This might seem wrong, note however that `Array.isArray(Array.prototype)` is true. - "prototype" : .jsArray, + "prototype": .jsArray ], methods: [ - "from" : [.jsAnything, .opt(.function()), .opt(.object())] => .jsArray, - "fromAsync" : [.jsAnything, .opt(.function()), .opt(.object())] => .jsPromise, - "isArray" : [.jsAnything] => .boolean, - "of" : [.jsAnything...] => .jsArray, + "from": [.jsAnything, .opt(.function()), .opt(.object())] => .jsArray, + "fromAsync": [.jsAnything, .opt(.function()), .opt(.object())] => .jsPromise, + "isArray": [.jsAnything] => .boolean, + "of": [.jsAnything...] => .jsArray, ] ) - static let jsArrayBufferPrototype = + public static let jsArrayBufferPrototype = createPrototypeObjectGroup(jsArrayBuffers, constructor: .jsArrayBufferConstructor) - static let jsArrayBufferConstructor = ObjectGroup( + public static let jsArrayBufferConstructor = ObjectGroup( name: "ArrayBufferConstructor", constructorPath: "ArrayBuffer", instanceType: .jsArrayBufferConstructor, properties: [ - "prototype" : jsArrayBufferPrototype.instanceType + "prototype": jsArrayBufferPrototype.instanceType ], methods: [ - "isView" : [.jsAnything] => .boolean + "isView": [.jsAnything] => .boolean ] ) - static let jsSharedArrayBufferPrototype = - createPrototypeObjectGroup(jsSharedArrayBuffers, constructor: .jsSharedArrayBufferConstructor) + public static let jsSharedArrayBufferPrototype = + createPrototypeObjectGroup( + jsSharedArrayBuffers, constructor: .jsSharedArrayBufferConstructor) - static let jsSharedArrayBufferConstructor = ObjectGroup( + public static let jsSharedArrayBufferConstructor = ObjectGroup( name: "SharedArrayBufferConstructor", constructorPath: "SharedArrayBuffer", instanceType: .jsSharedArrayBufferConstructor, properties: [ - "prototype" : jsSharedArrayBufferPrototype.instanceType + "prototype": jsSharedArrayBufferPrototype.instanceType ], methods: [:] ) - static let jsStringPrototype = + public static let jsStringPrototype = createPrototypeObjectGroup(jsStrings, constructor: .jsStringConstructor) /// Object group modelling the JavaScript String constructor builtin - static let jsStringConstructor = ObjectGroup( + public static let jsStringConstructor = ObjectGroup( name: "StringConstructor", constructorPath: "String", instanceType: .jsStringConstructor, properties: [ - "prototype" : jsStringPrototype.instanceType + "prototype": jsStringPrototype.instanceType ], methods: [ - "fromCharCode" : [.jsAnything...] => .jsString, - "fromCodePoint" : [.jsAnything...] => .jsString, - "raw" : [.jsAnything...] => .jsString + "fromCharCode": [.jsAnything...] => .jsString, + "fromCodePoint": [.jsAnything...] => .jsString, + "raw": [.jsAnything...] => .jsString, ] ) /// Object group modelling the JavaScript Symbol constructor builtin - static let jsSymbolConstructor = ObjectGroup( + public static let jsSymbolConstructor = ObjectGroup( name: "SymbolConstructor", constructorPath: "Symbol", instanceType: .jsSymbolConstructor, properties: [ - "iterator" : .jsSymbol, - "asyncIterator" : .jsSymbol, - "match" : .jsSymbol, - "matchAll" : .jsSymbol, - "replace" : .jsSymbol, - "search" : .jsSymbol, - "split" : .jsSymbol, - "hasInstance" : .jsSymbol, - "isConcatSpreadable" : .jsSymbol, - "unscopables" : .jsSymbol, - "species" : .jsSymbol, - "toPrimitive" : .jsSymbol, - "toStringTag" : .jsSymbol, - "dispose" : .jsSymbol, - "asyncDispose" : .jsSymbol + "iterator": .jsSymbol, + "asyncIterator": .jsSymbol, + "match": .jsSymbol, + "matchAll": .jsSymbol, + "replace": .jsSymbol, + "search": .jsSymbol, + "split": .jsSymbol, + "hasInstance": .jsSymbol, + "isConcatSpreadable": .jsSymbol, + "unscopables": .jsSymbol, + "species": .jsSymbol, + "toPrimitive": .jsSymbol, + "toStringTag": .jsSymbol, + "dispose": .jsSymbol, + "asyncDispose": .jsSymbol, ], methods: [ - "for" : [.string] => .jsSymbol, - "keyFor" : [.object(ofGroup: "Symbol")] => .jsString, + "for": [.string] => .jsSymbol, + "keyFor": [.object(ofGroup: "Symbol")] => .jsString, ] ) /// Object group modelling the JavaScript BigInt constructor builtin - static let jsBigIntConstructor = ObjectGroup( + public static let jsBigIntConstructor = ObjectGroup( name: "BigIntConstructor", constructorPath: "BigInt", instanceType: .jsBigIntConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [ - "asIntN" : [.number, .bigint] => .bigint, - "asUintN" : [.number, .bigint] => .bigint, + "asIntN": [.number, .bigint] => .bigint, + "asUintN": [.number, .bigint] => .bigint, ] ) - static let jsRegExpPrototype = createPrototypeObjectGroup(jsRegExps, constructor: .jsRegExpConstructor) + public static let jsRegExpPrototype = createPrototypeObjectGroup( + jsRegExps, constructor: .jsRegExpConstructor) /// Object group modelling the JavaScript RegExp constructor builtin - static let jsRegExpConstructor = ObjectGroup( + public static let jsRegExpConstructor = ObjectGroup( name: "RegExpConstructor", constructorPath: "RegExp", instanceType: .jsRegExpConstructor, properties: [ - "prototype" : jsRegExpPrototype.instanceType, + "prototype": jsRegExpPrototype.instanceType, "$1": .jsString, "$2": .jsString, "$3": .jsString, @@ -2395,100 +2910,100 @@ public extension ObjectGroup { "leftContext": .jsString, ], methods: [ - "escape" : [.string] => .jsString, + "escape": [.string] => .jsString ] ) /// Object group modelling the JavaScript Boolean constructor builtin - static let jsBooleanConstructor = ObjectGroup( + public static let jsBooleanConstructor = ObjectGroup( name: "BooleanConstructor", constructorPath: "Boolean", instanceType: .jsBooleanConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) /// Object group modelling the JavaScript Number constructor builtin - static let jsNumberConstructor = ObjectGroup( + public static let jsNumberConstructor = ObjectGroup( name: "NumberConstructor", constructorPath: "Number", instanceType: .jsNumberConstructor, properties: [ - "prototype" : .object(), + "prototype": .object(), // TODO: should there be a .jsNumber type? - "EPSILON" : .number, - "MAX_SAFE_INTEGER" : .number, - "MAX_VALUE" : .number, - "MIN_SAFE_INTEGER" : .number, - "MIN_VALUE" : .number, - "NaN" : .number, - "NEGATIVE_INFINITY" : .number, - "POSITIVE_INFINITY" : .number, + "EPSILON": .number, + "MAX_SAFE_INTEGER": .number, + "MAX_VALUE": .number, + "MIN_SAFE_INTEGER": .number, + "MIN_VALUE": .number, + "NaN": .number, + "NEGATIVE_INFINITY": .number, + "POSITIVE_INFINITY": .number, ], methods: [ - "isNaN" : [.jsAnything] => .boolean, - "isFinite" : [.jsAnything] => .boolean, - "isInteger" : [.jsAnything] => .boolean, - "isSafeInteger" : [.jsAnything] => .boolean, - "parseFloat" : [.string] => .float, - "parseInt" : [.string] => .integer, + "isNaN": [.jsAnything] => .boolean, + "isFinite": [.jsAnything] => .boolean, + "isInteger": [.jsAnything] => .boolean, + "isSafeInteger": [.jsAnything] => .boolean, + "parseFloat": [.string] => .float, + "parseInt": [.string] => .integer, ] ) /// Object group modelling the JavaScript Math builtin - static let jsMathObject = ObjectGroup( + public static let jsMathObject = ObjectGroup( name: "Math", instanceType: .jsMathObject, properties: [ - "E" : .number, - "PI" : .number, - "LN10" : .number, - "LN2" : .number, - "LOG10E" : .number, - "LOG2E" : .number, - "SQRT1_2" : .number, - "SQRT2" : .number, + "E": .number, + "PI": .number, + "LN10": .number, + "LN2": .number, + "LOG10E": .number, + "LOG2E": .number, + "SQRT1_2": .number, + "SQRT2": .number, ], methods: [ - "abs" : [.jsAnything] => .number, - "acos" : [.jsAnything] => .number, - "acosh" : [.jsAnything] => .number, - "asin" : [.jsAnything] => .number, - "asinh" : [.jsAnything] => .number, - "atan" : [.jsAnything] => .number, - "atanh" : [.jsAnything] => .number, - "atan2" : [.jsAnything, .jsAnything] => .number, - "cbrt" : [.jsAnything] => .number, - "ceil" : [.jsAnything] => .number, - "clz32" : [.jsAnything] => .number, - "cos" : [.jsAnything] => .number, - "cosh" : [.jsAnything] => .number, - "exp" : [.jsAnything] => .number, - "expm1" : [.jsAnything] => .number, - "floor" : [.jsAnything] => .number, - "fround" : [.jsAnything] => .number, - "f16round" : [.jsAnything] => .number, - "hypot" : [.jsAnything...] => .number, - "imul" : [.jsAnything, .jsAnything] => .integer, - "log" : [.jsAnything] => .number, - "log1p" : [.jsAnything] => .number, - "log10" : [.jsAnything] => .number, - "log2" : [.jsAnything] => .number, - "max" : [.jsAnything...] => .number, - "min" : [.jsAnything...] => .number, - "pow" : [.jsAnything, .jsAnything] => .number, - "random" : [] => .number, - "round" : [.jsAnything] => .number, - "sign" : [.jsAnything] => .number, - "sin" : [.jsAnything] => .number, - "sinh" : [.jsAnything] => .number, - "sqrt" : [.jsAnything] => .number, - "sumPrecise" : [.iterable] => .number, - "tan" : [.jsAnything] => .number, - "tanh" : [.jsAnything] => .number, - "trunc" : [.jsAnything] => .number, + "abs": [.jsAnything] => .number, + "acos": [.jsAnything] => .number, + "acosh": [.jsAnything] => .number, + "asin": [.jsAnything] => .number, + "asinh": [.jsAnything] => .number, + "atan": [.jsAnything] => .number, + "atanh": [.jsAnything] => .number, + "atan2": [.jsAnything, .jsAnything] => .number, + "cbrt": [.jsAnything] => .number, + "ceil": [.jsAnything] => .number, + "clz32": [.jsAnything] => .number, + "cos": [.jsAnything] => .number, + "cosh": [.jsAnything] => .number, + "exp": [.jsAnything] => .number, + "expm1": [.jsAnything] => .number, + "floor": [.jsAnything] => .number, + "fround": [.jsAnything] => .number, + "f16round": [.jsAnything] => .number, + "hypot": [.jsAnything...] => .number, + "imul": [.jsAnything, .jsAnything] => .integer, + "log": [.jsAnything] => .number, + "log1p": [.jsAnything] => .number, + "log10": [.jsAnything] => .number, + "log2": [.jsAnything] => .number, + "max": [.jsAnything...] => .number, + "min": [.jsAnything...] => .number, + "pow": [.jsAnything, .jsAnything] => .number, + "random": [] => .number, + "round": [.jsAnything] => .number, + "sign": [.jsAnything] => .number, + "sin": [.jsAnything] => .number, + "sinh": [.jsAnything] => .number, + "sqrt": [.jsAnything] => .number, + "sumPrecise": [.iterable] => .number, + "tan": [.jsAnything] => .number, + "tanh": [.jsAnything] => .number, + "trunc": [.jsAnything] => .number, ] ) @@ -2496,83 +3011,91 @@ public extension ObjectGroup { /// Note that the typing here is not perfect: .someTypedArray doesn't have precise type /// information. The parameters and results typed as .jsAnything are either .number or .bigint /// depending on the type of the TypedArray that is passed as the first argument. - static let jsAtomicsObject = ObjectGroup( + public static let jsAtomicsObject = ObjectGroup( name: "Atomics", instanceType: .jsAtomicsObject, properties: [:], methods: [ - "add" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "and" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "compareExchange" : [.plain(.someTypedArray), .integer, .jsAnything, .jsAnything] => .jsAnything, - "exchange" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "isLockFree" : [.integer] => .boolean, - "load" : [.plain(.someTypedArray), .integer] => .jsAnything, - "notify" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), .integer, .opt(.integer)] => .integer, - "or" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "pause" : [.opt(.integer)] => .undefined, - "store" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "sub" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "wait" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), - .integer, .jsAnything, .opt(.number)] => .string, - "waitAsync" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), - .integer, .jsAnything, .opt(.number)] => .object(withProperties: ["async", "value"]), - "xor" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "add": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "and": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "compareExchange": [.plain(.someTypedArray), .integer, .jsAnything, .jsAnything] + => .jsAnything, + "exchange": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "isLockFree": [.integer] => .boolean, + "load": [.plain(.someTypedArray), .integer] => .jsAnything, + "notify": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), .integer, + .opt(.integer), + ] => .integer, + "or": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "pause": [.opt(.integer)] => .undefined, + "store": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "sub": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "wait": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), + .integer, .jsAnything, .opt(.number), + ] => .string, + "waitAsync": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), + .integer, .jsAnything, .opt(.number), + ] => .object(withProperties: ["async", "value"]), + "xor": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, ] ) /// ObjectGroup modelling the JavaScript JSON builtin - static let jsJSONObject = ObjectGroup( + public static let jsJSONObject = ObjectGroup( name: "JSON", instanceType: .jsJSONObject, properties: [:], methods: [ - "parse" : [.string, .opt(.function())] => .jsAnything, - "stringify" : [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString, - "rawJSON" : [.plain(.string | .number | .boolean)] => .jsAnything, - "isRawJSON" : [.jsAnything] => .boolean, + "parse": [.string, .opt(.function())] => .jsAnything, + "stringify": [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString, + "rawJSON": [.plain(.string | .number | .boolean)] => .jsAnything, + "isRawJSON": [.jsAnything] => .boolean, ] ) /// ObjectGroup modelling the JavaScript Reflect builtin - static let jsReflectObject = ObjectGroup( + public static let jsReflectObject = ObjectGroup( name: "Reflect", instanceType: .jsReflectObject, properties: [:], methods: [ - "apply" : [.function(), .jsAnything, .object()] => .jsAnything, - "construct" : [.constructor(), .object(), .opt(.object())] => .jsAnything, - "defineProperty" : [.object(), .string, .object()] => .boolean, - "deleteProperty" : [.object(), .string] => .boolean, - "get" : [.object(), .string, .opt(.object())] => .jsAnything, - "getOwnPropertyDescriptor" : [.object(), .string] => .jsAnything, - "getPrototypeOf" : [.object()] => .jsAnything, - "has" : [.object(), .string] => .boolean, - "isExtensible" : [.object()] => .boolean, - "ownKeys" : [.object()] => .jsArray, - "preventExtensions" : [.object()] => .boolean, - "set" : [.object(), .string, .jsAnything, .opt(.object())] => .boolean, - "setPrototypeOf" : [.object(), .object()] => .boolean, + "apply": [.function(), .jsAnything, .object()] => .jsAnything, + "construct": [.constructor(), .object(), .opt(.object())] => .jsAnything, + "defineProperty": [.object(), .string, .object()] => .boolean, + "deleteProperty": [.object(), .string] => .boolean, + "get": [.object(), .string, .opt(.object())] => .jsAnything, + "getOwnPropertyDescriptor": [.object(), .string] => .jsAnything, + "getPrototypeOf": [.object()] => .jsAnything, + "has": [.object(), .string] => .boolean, + "isExtensible": [.object()] => .boolean, + "ownKeys": [.object()] => .jsArray, + "preventExtensions": [.object()] => .boolean, + "set": [.object(), .string, .jsAnything, .opt(.object())] => .boolean, + "setPrototypeOf": [.object(), .object()] => .boolean, ] ) /// ObjectGroup modelling JavaScript Error objects - static func jsError(_ variant: String) -> ObjectGroup { + public static func jsError(_ variant: String) -> ObjectGroup { return ObjectGroup( name: variant, instanceType: .jsError(variant), properties: [ - "message" : .jsString, - "name" : .jsString, - "cause" : .jsAnything, - "stack" : .jsString, + "message": .jsString, + "name": .jsString, + "cause": .jsAnything, + "stack": .jsString, ], methods: [ - "toString" : [] => .jsString, + "toString": [] => .jsString ] ) } - static func jsErrorPrototype(_ variant: String) -> ObjectGroup { + public static func jsErrorPrototype(_ variant: String) -> ObjectGroup { return createPrototypeObjectGroup( jsError(variant), constructor: .jsErrorConstructor(variant), @@ -2582,7 +3105,7 @@ public extension ObjectGroup { ]) } - static func jsErrorConstructor(_ variant: String) -> ObjectGroup { + public static func jsErrorConstructor(_ variant: String) -> ObjectGroup { return ObjectGroup( name: "\(variant)Constructor", constructorPath: variant, @@ -2601,7 +3124,7 @@ public extension ObjectGroup { // TODO(mliedtke): We need to construct these to make code generators be able to provide // somewhat reasonable compile options. - static let jsWebAssemblyCompileOptions = ObjectGroup( + public static let jsWebAssemblyCompileOptions = ObjectGroup( name: "WebAssemblyCompileOptions", instanceType: nil, properties: [ @@ -2613,18 +3136,19 @@ public extension ObjectGroup { // Note: This supports all typed arrays, however, that would add a huge amount of overloads, so // we only add a few selected typed arrays here. - static let wasmBufferTypes = [ + public static let wasmBufferTypes = [ ILType.jsArrayBuffer, .jsSharedArrayBuffer, .jsTypedArray("Int8Array"), - .jsTypedArray("Float32Array"), .jsTypedArray("BigUint64Array")] + .jsTypedArray("Float32Array"), .jsTypedArray("BigUint64Array"), + ] - static let jsWebAssemblyModule = ObjectGroup( + public static let jsWebAssemblyModule = ObjectGroup( name: "WebAssembly.Module", instanceType: .jsWebAssemblyModule, properties: [:], methods: [:] ) - static let jsWebAssemblyModuleConstructor = ObjectGroup( + public static let jsWebAssemblyModuleConstructor = ObjectGroup( name: "WebAssemblyModuleConstructor", constructorPath: "WebAssembly.Module", instanceType: .jsWebAssemblyModuleConstructor, @@ -2632,88 +3156,89 @@ public extension ObjectGroup { "prototype": .object() ], methods: [ - "customSections": [.plain(jsWebAssemblyModule.instanceType), .plain(.jsString)] => .jsArray, + "customSections": [.plain(jsWebAssemblyModule.instanceType), .plain(.jsString)] + => .jsArray, "exports": [.plain(jsWebAssemblyModule.instanceType)] => .jsArray, "imports": [.plain(jsWebAssemblyModule.instanceType)] => .jsArray, ] ) - static let jsWebAssemblyGlobalPrototype = + public static let jsWebAssemblyGlobalPrototype = createPrototypeObjectGroup(jsWasmGlobal, constructor: .jsWebAssemblyGlobalConstructor) - static let jsWebAssemblyGlobalConstructor = ObjectGroup( + public static let jsWebAssemblyGlobalConstructor = ObjectGroup( name: "WebAssemblyGlobalConstructor", constructorPath: "WebAssembly.Global", instanceType: .jsWebAssemblyGlobalConstructor, properties: [ - "prototype": jsWebAssemblyGlobalPrototype.instanceType, + "prototype": jsWebAssemblyGlobalPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyInstanceConstructor = ObjectGroup( + public static let jsWebAssemblyInstanceConstructor = ObjectGroup( name: "WebAssemblyInstanceConstructor", constructorPath: "WebAssembly.Instance", instanceType: .jsWebAssemblyInstanceConstructor, properties: [ - "prototype": .object(), + "prototype": .object() ], methods: [:] ) - static let jsWebAssemblyInstance = ObjectGroup( + public static let jsWebAssemblyInstance = ObjectGroup( name: "WebAssembly.Instance", instanceType: .jsWebAssemblyInstance, properties: [ - "exports": .object(), + "exports": .object() ], methods: [:] ) - static let jsWebAssemblyMemoryPrototype = + public static let jsWebAssemblyMemoryPrototype = createPrototypeObjectGroup(jsWasmMemory, constructor: .jsWebAssemblyMemoryConstructor) - static let jsWebAssemblyMemoryConstructor = ObjectGroup( + public static let jsWebAssemblyMemoryConstructor = ObjectGroup( name: "WebAssemblyMemoryConstructor", constructorPath: "WebAssembly.Memory", instanceType: .jsWebAssemblyMemoryConstructor, properties: [ - "prototype": jsWebAssemblyMemoryPrototype.instanceType, + "prototype": jsWebAssemblyMemoryPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyTablePrototype = + public static let jsWebAssemblyTablePrototype = createPrototypeObjectGroup(wasmTable, constructor: .jsWebAssemblyTableConstructor) - static let jsWebAssemblyTableConstructor = ObjectGroup( + public static let jsWebAssemblyTableConstructor = ObjectGroup( name: "WebAssemblyTableConstructor", constructorPath: "WebAssembly.Table", instanceType: .jsWebAssemblyTableConstructor, properties: [ - "prototype": jsWebAssemblyTablePrototype.instanceType, + "prototype": jsWebAssemblyTablePrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyTagPrototype = + public static let jsWebAssemblyTagPrototype = createPrototypeObjectGroup(jsWasmTag, constructor: .jsWebAssemblyTagConstructor) - static let jsWebAssemblyTagConstructor = ObjectGroup( + public static let jsWebAssemblyTagConstructor = ObjectGroup( name: "WebAssemblyTagConstructor", constructorPath: "WebAssembly.Tag", instanceType: .jsWebAssemblyTagConstructor, properties: [ - "prototype": jsWebAssemblyTagPrototype.instanceType, + "prototype": jsWebAssemblyTagPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyException = ObjectGroup( + public static let jsWebAssemblyException = ObjectGroup( name: "WebAssembly.Exception", instanceType: nil, properties: [ - "stack": .string | .undefined, + "stack": .string | .undefined ], methods: [ "getArg": [.plain(jsWasmTag.instanceType), .plain(.integer)] => .jsAnything, @@ -2721,16 +3246,16 @@ public extension ObjectGroup { ] ) - static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup( + public static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup( jsWebAssemblyException, constructor: .jsWebAssemblyExceptionConstructor) - static let jsWebAssemblyExceptionConstructor = ObjectGroup( + public static let jsWebAssemblyExceptionConstructor = ObjectGroup( name: "WebAssemblyExceptionConstructor", constructorPath: "WebAssembly.Exception", instanceType: .jsWebAssemblyExceptionConstructor, properties: [ - "prototype": jsWebAssemblyExceptionPrototype.instanceType, + "prototype": jsWebAssemblyExceptionPrototype.instanceType ], methods: [:] ) @@ -2748,7 +3273,9 @@ public extension ObjectGroup { ) fileprivate static let webAssemblyErrorConstructorType = - ILType.constructor([.opt(.string), .opt(.object() | .string), .opt(.string)] => jsWebAssemblyError.instanceType) + ILType.constructor( + [.opt(.string), .opt(.object() | .string), .opt(.string)] + => jsWebAssemblyError.instanceType) + .object(ofGroup: "WebAssemblyErrorConstructor", withProperties: ["prototype"]) fileprivate static let jsWebAssemblyErrorPrototype = createPrototypeObjectGroup( @@ -2764,18 +3291,20 @@ public extension ObjectGroup { name: "WebAssemblyErrorConstructor", instanceType: webAssemblyErrorConstructorType, properties: [ - "prototype": jsWebAssemblyErrorPrototype.instanceType, + "prototype": jsWebAssemblyErrorPrototype.instanceType ], methods: [:] ) - fileprivate static let webAssemblySuspendingConstructorType = ILType.constructor([.plain(.function())] => .object()) + fileprivate static let webAssemblySuspendingConstructorType = ILType.constructor( + [.plain(.function())] => .object()) - static let jsWebAssembly = ObjectGroup( + public static let jsWebAssembly = ObjectGroup( name: "WebAssembly", instanceType: nil, properties: [ - "JSTag": .object(ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true)), + "JSTag": .object( + ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true)), "Module": .jsWebAssemblyModuleConstructor, "Global": .jsWebAssemblyGlobalConstructor, "Instance": .jsWebAssemblyInstanceConstructor, @@ -2791,62 +3320,73 @@ public extension ObjectGroup { ], overloads: [ "compile": wasmBufferTypes.map { - [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + }, // TODO: The first parameter should be a Response which Fuzzilli doesn't know as it is // mostly used by WebAPIs like fetch(). "compileStreaming": [ - [.object(), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise], + [.object(), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + ], "instantiate": wasmBufferTypes.map { - [.plain($0), /*imports*/ .opt(.object()), - .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [ + .plain($0), /*imports*/ .opt(.object()), + .opt(jsWebAssemblyCompileOptions.instanceType), + ] => .jsPromise + }, // TODO: Same as compileStreaming(), the first parameter has to be a Response. "instantiateStreaming": [ - [.object(), /*imports*/ .opt(.object()), - .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise], + [ + .object(), /*imports*/ .opt(.object()), + .opt(jsWebAssemblyCompileOptions.instanceType), + ] => .jsPromise + ], "validate": wasmBufferTypes.map { - [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + }, // The argument needs to be an exported Wasm function. Fuzzilli's type system does not // distinguish between Wasm and JS functions, so we can't express this precisely. - "promising": [[.function()] => .function()] + "promising": [[.function()] => .function()], ] ) /// ObjectGroup modelling JavaScript WebAssembly Global objects. - static let jsWasmGlobal = ObjectGroup( + public static let jsWasmGlobal = ObjectGroup( name: "WasmGlobal", instanceType: nil, properties: [ // TODO: Try using precise JS types based on the global's underlying valuetype (e.g. float for f32 and f64). - "value" : .jsAnything + "value": .jsAnything ], methods: ["valueOf": [] => .jsAnything] ) /// ObjectGroup modelling JavaScript WebAssembly Memory objects. - static let jsWasmMemory = ObjectGroup( + public static let jsWasmMemory = ObjectGroup( name: "WasmMemory", - instanceType: .object(ofGroup: "WasmMemory", withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"]), + instanceType: .object( + ofGroup: "WasmMemory", withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"]), properties: [ - "buffer" : .jsArrayBuffer | .jsSharedArrayBuffer + "buffer": .jsArrayBuffer | .jsSharedArrayBuffer ], methods: [ - "grow" : [.number] => .number, - "toResizableBuffer" : [] => (.jsArrayBuffer | .jsSharedArrayBuffer), - "toFixedLengthBuffer" : [] => (.jsArrayBuffer | .jsSharedArrayBuffer), + "grow": [.number] => .number, + "toResizableBuffer": [] => (.jsArrayBuffer | .jsSharedArrayBuffer), + "toFixedLengthBuffer": [] => (.jsArrayBuffer | .jsSharedArrayBuffer), ] ) // TOOD(mliedtke): Reconsider whether WebAssembly.Tag and WebAssembly.JSTag should share the // same object group. When split, we can register the type() prototype method. - static let jsWasmTag = ObjectGroup( + public static let jsWasmTag = ObjectGroup( name: "WasmTag", - instanceType: nil, // inferred + instanceType: nil, // inferred properties: [:], methods: [:] ) /// ObjectGroup modelling JavaScript WebAssembly Table objects - static let wasmTable = ObjectGroup( + public static let wasmTable = ObjectGroup( name: "WasmTable", instanceType: .wasmTable, properties: [ @@ -2859,7 +3399,7 @@ public extension ObjectGroup { ] ) - static let jsWasmSuspendingObject = ObjectGroup( + public static let jsWasmSuspendingObject = ObjectGroup( name: "WasmSuspendingObject", instanceType: .object(ofGroup: "WasmSuspendingObject"), properties: [:], @@ -2869,24 +3409,36 @@ public extension ObjectGroup { // Temporal types // Helpers for constructing common signatures - private static func temporalAddSubtractSignature(forType: ILType, needsOverflow: Bool) -> [Signature] { + private static func temporalAddSubtractSignature(forType: ILType, needsOverflow: Bool) + -> [Signature] + { if needsOverflow { - return jsTemporalDurationLikeParameters.map { [.plain($0), .opt(jsTemporalOverflowSettings)] => forType } + return jsTemporalDurationLikeParameters.map { + [.plain($0), .opt(jsTemporalOverflowSettings)] => forType + } } else { return jsTemporalDurationLikeParameters.map { [.plain($0)] => forType } } } private static func temporalUntilSinceSignature(possibleParams: [ILType]) -> [Signature] { - return possibleParams.map { [.plain($0), .opt(jsTemporalDifferenceSettings)] => .jsTemporalDuration } + return possibleParams.map { + [.plain($0), .opt(jsTemporalDifferenceSettings)] => .jsTemporalDuration + } } - private static func temporalFromSignature(forType: ILType, possibleParams: [ILType], settingsArg: ILType? = nil) -> [Signature] { + private static func temporalFromSignature( + forType: ILType, possibleParams: [ILType], settingsArg: ILType? = nil + ) -> [Signature] { if let settingsArg { return possibleParams.map { [.plain($0), .opt(settingsArg)] => forType } } else { - return possibleParams.map { [.plain($0), .opt(jsTemporalDifferenceSettings)] => forType } + return possibleParams.map { + [.plain($0), .opt(jsTemporalDifferenceSettings)] => forType + } } } - private static func temporalCompareSignature(possibleParams: [ILType], settingsArg: ILType? = nil) -> [Signature] { + private static func temporalCompareSignature( + possibleParams: [ILType], settingsArg: ILType? = nil + ) -> [Signature] { possibleParams.flatMap { param1 in return possibleParams.map { param2 in if let settingsArg { @@ -2902,7 +3454,9 @@ public extension ObjectGroup { return possibleParams.map { [.plain($0)] => .boolean } } - private static func temporalTimeZoneLikeSignature(signature: (ILType) -> Signature) -> [Signature] { + private static func temporalTimeZoneLikeSignature(signature: (ILType) -> Signature) + -> [Signature] + { return [ signature(jsTemporalTimeZoneLike), signature(.jsTemporalZonedDateTime), @@ -2910,39 +3464,43 @@ public extension ObjectGroup { } /// Object group modelling the JavaScript Temporal builtin - static let jsTemporalObject = ObjectGroup( + public static let jsTemporalObject = ObjectGroup( name: "Temporal", instanceType: .jsTemporalObject, properties: [ - "Instant" : .jsTemporalInstantConstructor, - "Duration" : .jsTemporalDurationConstructor, - "PlainTime" : .jsTemporalPlainTimeConstructor, - "PlainYearMonth" : .jsTemporalPlainYearMonthConstructor, - "PlainMonthDay" : .jsTemporalPlainMonthDayConstructor, - "PlainDate" : .jsTemporalPlainDateConstructor, - "PlainDateTime" : .jsTemporalPlainDateTimeConstructor, - "ZonedDateTime" : .jsTemporalZonedDateTimeConstructor, + "Instant": .jsTemporalInstantConstructor, + "Duration": .jsTemporalDurationConstructor, + "PlainTime": .jsTemporalPlainTimeConstructor, + "PlainYearMonth": .jsTemporalPlainYearMonthConstructor, + "PlainMonthDay": .jsTemporalPlainMonthDayConstructor, + "PlainDate": .jsTemporalPlainDateConstructor, + "PlainDateTime": .jsTemporalPlainDateTimeConstructor, + "ZonedDateTime": .jsTemporalZonedDateTimeConstructor, "Now": .jsTemporalNow, ], methods: [:] ) - static let jsTemporalNow = ObjectGroup( + public static let jsTemporalNow = ObjectGroup( name: "Temporal.Now", instanceType: .jsTemporalNow, properties: [:], overloads: [ "timeZoneId": [[] => .string], "instant": [[] => .jsTemporalInstant], - "plainDateTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainDateTime }, - "zonedDateTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalZonedDateTime }, + "plainDateTimeISO": temporalTimeZoneLikeSignature { + [.opt($0)] => .jsTemporalPlainDateTime + }, + "zonedDateTimeISO": temporalTimeZoneLikeSignature { + [.opt($0)] => .jsTemporalZonedDateTime + }, "plainDateISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainDate }, "plainTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainTime }, ] ) /// ObjectGroup modelling JavaScript Temporal.Instant objects - static let jsTemporalInstant = ObjectGroup( + public static let jsTemporalInstant = ObjectGroup( name: "Temporal.Instant", instanceType: .jsTemporalInstant, properties: [ @@ -2951,7 +3509,8 @@ public extension ObjectGroup { ], overloads: [ "add": temporalAddSubtractSignature(forType: .jsTemporalInstant, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalInstant, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalInstant, needsOverflow: false), "until": temporalUntilSinceSignature(possibleParams: jsTemporalInstantLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalInstantLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalInstant], @@ -2959,30 +3518,33 @@ public extension ObjectGroup { "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toZonedDateTimeISO": temporalTimeZoneLikeSignature { [.plain($0)] => .jsTemporalZonedDateTime }, + "toZonedDateTimeISO": temporalTimeZoneLikeSignature { + [.plain($0)] => .jsTemporalZonedDateTime + }, ] ) - static let jsTemporalInstantPrototype = + public static let jsTemporalInstantPrototype = createPrototypeObjectGroup(jsTemporalInstant, constructor: .jsTemporalInstantConstructor) /// ObjectGroup modelling the JavaScript Temporal.Instant constructor - static let jsTemporalInstantConstructor = ObjectGroup( + public static let jsTemporalInstantConstructor = ObjectGroup( name: "TemporalInstantConstructor", constructorPath: "Temporal.Instant", instanceType: .jsTemporalInstantConstructor, properties: [ - "prototype" : jsTemporalInstantPrototype.instanceType + "prototype": jsTemporalInstantPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalInstant, possibleParams: jsTemporalInstantLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalInstant, possibleParams: jsTemporalInstantLikeParameters), "fromEpochMilliseconds": [[.number] => .jsTemporalInstant], "fromEpochNanoseconds": [[.bigint] => .jsTemporalInstant], "compare": temporalCompareSignature(possibleParams: jsTemporalInstantLikeParameters), ] ) /// ObjectGroup modelling JavaScript Temporal.Duration objects - static let jsTemporalDuration = ObjectGroup( + public static let jsTemporalDuration = ObjectGroup( name: "Temporal.Duration", instanceType: .jsTemporalDuration, properties: [ @@ -3004,7 +3566,8 @@ public extension ObjectGroup { "negated": [[] => .jsTemporalDuration], "abs": [[] => .jsTemporalDuration], "add": temporalAddSubtractSignature(forType: .jsTemporalDuration, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalDuration, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalDuration, needsOverflow: false), "round": [[.plain(jsTemporalDurationRoundToSettings)] => .jsTemporalDuration], "total": [[.plain(jsTemporalDurationTotalOfSettings)] => .jsTemporalDuration], "toString": [[.opt(jsTemporalToStringSettings)] => .string], @@ -3013,24 +3576,27 @@ public extension ObjectGroup { ] ) - static let jsTemporalDurationPrototype = + public static let jsTemporalDurationPrototype = createPrototypeObjectGroup(jsTemporalDuration, constructor: .jsTemporalDurationConstructor) /// ObjectGroup modelling the JavaScript Temporal.Duration constructor - static let jsTemporalDurationConstructor = ObjectGroup( + public static let jsTemporalDurationConstructor = ObjectGroup( name: "TemporalDurationConstructor", constructorPath: "Temporal.Duration", instanceType: .jsTemporalDurationConstructor, properties: [ - "prototype" : jsTemporalDurationPrototype.instanceType + "prototype": jsTemporalDurationPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalDuration, possibleParams: jsTemporalDurationLikeParameters), - "compare": temporalCompareSignature(possibleParams: jsTemporalDurationLikeParameters, settingsArg: jsTemporalDurationCompareSettings), + "from": temporalFromSignature( + forType: .jsTemporalDuration, possibleParams: jsTemporalDurationLikeParameters), + "compare": temporalCompareSignature( + possibleParams: jsTemporalDurationLikeParameters, + settingsArg: jsTemporalDurationCompareSettings), ] ) - static let jsTemporalPlainTime = ObjectGroup( + public static let jsTemporalPlainTime = ObjectGroup( name: "Temporal.PlainTime", instanceType: .jsTemporalPlainTime, properties: [ @@ -3042,9 +3608,16 @@ public extension ObjectGroup { "nanosecond": .number, ], overloads: [ - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainTime, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainTime, needsOverflow: false), - "with": [[.plain(jsTemporalPlainTimeLikeObject.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainTime], + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainTime, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainTime, needsOverflow: false), + "with": [ + [ + .plain(jsTemporalPlainTimeLikeObject.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainTime + ], "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainTimeLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalPlainTime], @@ -3055,19 +3628,21 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainTimePrototype = - createPrototypeObjectGroup(jsTemporalPlainTime, constructor: .jsTemporalPlainTimeConstructor) + public static let jsTemporalPlainTimePrototype = + createPrototypeObjectGroup( + jsTemporalPlainTime, constructor: .jsTemporalPlainTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainTime constructor - static let jsTemporalPlainTimeConstructor = ObjectGroup( + public static let jsTemporalPlainTimeConstructor = ObjectGroup( name: "TemporalPlainTimeConstructor", constructorPath: "Temporal.PlainTime", instanceType: .jsTemporalPlainTimeConstructor, properties: [ - "prototype" : jsTemporalPlainTimePrototype.instanceType + "prototype": jsTemporalPlainTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainTime, possibleParams: jsTemporalPlainTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainTime, possibleParams: jsTemporalPlainTimeLikeParameters), "compare": temporalCompareSignature(possibleParams: jsTemporalPlainTimeLikeParameters), ] ) @@ -3083,45 +3658,60 @@ public extension ObjectGroup { "daysInYear": .integer, "monthsInYear": .integer, "inLeapYear": .boolean, - ]; + ] - static let jsTemporalPlainYearMonth = ObjectGroup( + public static let jsTemporalPlainYearMonth = ObjectGroup( name: "Temporal.PlainYearMonth", instanceType: .jsTemporalPlainYearMonth, properties: jsTemporalPlainYearMonthProperties, overloads: [ - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainYearMonth], - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainYearMonth, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainYearMonth, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainYearMonth + ], + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainYearMonth, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainYearMonth, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toPlainDate": [[.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate], + "toPlainDate": [ + [.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate + ], ] ) - static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup( jsTemporalPlainYearMonth, constructor: .jsTemporalPlainYearMonthConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainYearMonth constructor - static let jsTemporalPlainYearMonthConstructor = ObjectGroup( + public static let jsTemporalPlainYearMonthConstructor = ObjectGroup( name: "TemporalPlainYearMonthConstructor", constructorPath: "Temporal.PlainYearMonth", instanceType: .jsTemporalPlainYearMonthConstructor, properties: [ - "prototype" : jsTemporalPlainYearMonthPrototype.instanceType + "prototype": jsTemporalPlainYearMonthPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainYearMonth, possibleParams: jsTemporalPlainYearMonthLikeParameters), - "compare": temporalCompareSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainYearMonth, + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "compare": temporalCompareSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), ] ) - static let jsTemporalPlainMonthDay = ObjectGroup( + public static let jsTemporalPlainMonthDay = ObjectGroup( name: "Temporal.PlainMonthDay", instanceType: .jsTemporalPlainMonthDay, properties: [ @@ -3130,149 +3720,211 @@ public extension ObjectGroup { "day": .integer, ], overloads: [ - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainYearMonth], - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainYearMonth + ], + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toPlainDate": [[.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate], + "toPlainDate": [ + [.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate + ], ] ) - static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup( jsTemporalPlainMonthDay, constructor: .jsTemporalPlainMonthDayConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainMonthDay constructor. - static let jsTemporalPlainMonthDayConstructor = ObjectGroup( + public static let jsTemporalPlainMonthDayConstructor = ObjectGroup( name: "TemporalPlainMonthDayConstructor", constructorPath: "Temporal.PlainMonthDay", instanceType: .jsTemporalPlainMonthDayConstructor, properties: [ - "prototype" : jsTemporalPlainMonthDayPrototype.instanceType + "prototype": jsTemporalPlainMonthDayPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainMonthDay, possibleParams: jsTemporalPlainMonthDayLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainMonthDay, + possibleParams: jsTemporalPlainMonthDayLikeParameters) ] ) - static let jsTemporalPlainDate = ObjectGroup( + public static let jsTemporalPlainDate = ObjectGroup( name: "Temporal.PlainDate", instanceType: .jsTemporalPlainDate, - properties: mergeFields(jsTemporalPlainYearMonthProperties, [ - "day": .integer, - "dayOfWeek": .integer, - "dayOfYear": .integer, - "weekOfYear": .integer, - "yearOfWeek": .integer, - "daysInWeek": .integer, - ]), + properties: mergeFields( + jsTemporalPlainYearMonthProperties, + [ + "day": .integer, + "dayOfWeek": .integer, + "dayOfYear": .integer, + "weekOfYear": .integer, + "yearOfWeek": .integer, + "daysInWeek": .integer, + ]), overloads: [ "toPlainYearMonth": [[] => .jsTemporalPlainYearMonth], "toPlainMonthDay": [[] => .jsTemporalPlainMonthDay], "add": temporalAddSubtractSignature(forType: .jsTemporalPlainDate, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainDate, needsOverflow: true), - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainDate], + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainDate, needsOverflow: true), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainDate + ], "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate], "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateLikeParameters), "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainDateLikeParameters), - "toPlainDateTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalPlainDateTime}, - "toZonedDateTime": temporalTimeZoneLikeSignature { [.plain($0)] => .jsTemporalZonedDateTime } + "toPlainDateTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalPlainDateTime + }, + "toZonedDateTime": temporalTimeZoneLikeSignature { + [.plain($0)] => .jsTemporalZonedDateTime + } // Can also accept an object with timezone/time fields - + [[.plain(OptionsBag.jsTemporalPlainDateToZDTSettings.group.instanceType)] => .jsTemporalZonedDateTime], + + [ + [.plain(OptionsBag.jsTemporalPlainDateToZDTSettings.group.instanceType)] + => .jsTemporalZonedDateTime + ], "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], ] ) - static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup( jsTemporalPlainDate, constructor: .jsTemporalPlainDateConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDate constructor - static let jsTemporalPlainDateConstructor = ObjectGroup( + public static let jsTemporalPlainDateConstructor = ObjectGroup( name: "TemporalPlainDateConstructor", constructorPath: "Temporal.PlainDate", instanceType: .jsTemporalPlainDateConstructor, properties: [ - "prototype" : jsTemporalPlainDatePrototype.instanceType + "prototype": jsTemporalPlainDatePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainDate, possibleParams: jsTemporalPlainDateLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainDate, possibleParams: jsTemporalPlainDateLikeParameters), "compare": temporalCompareSignature(possibleParams: jsTemporalPlainDateLikeParameters), ] ) - static let jsTemporalPlainDateTime = ObjectGroup( + public static let jsTemporalPlainDateTime = ObjectGroup( name: "Temporal.PlainDateTime", instanceType: .jsTemporalPlainDateTime, properties: mergeFields(jsTemporalPlainDate.properties, jsTemporalPlainTime.properties), overloads: [ - "with": [[.plain(jsTemporalPlainDateTimeLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainDateTime], - "withPlainTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalPlainDateTime}, + "with": [ + [ + .plain(jsTemporalPlainDateTimeLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainDateTime + ], + "withPlainTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalPlainDateTime + }, "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalPlainDateTime], - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainDateTime, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainDateTime, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainDateTime, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainDateTime, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalPlainDateTime], - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toZonedDateTime": temporalTimeZoneLikeSignature { [.plain($0), .opt(OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType)] => .jsTemporalZonedDateTime }, + "toZonedDateTime": temporalTimeZoneLikeSignature { + [ + .plain($0), + .opt(OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType), + ] => .jsTemporalZonedDateTime + }, "toPlainDate": [[] => .jsTemporalPlainDate], "toPlainTime": [[] => .jsTemporalPlainTime], ] ) - static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup( jsTemporalPlainDateTime, constructor: .jsTemporalPlainDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDateTime constructor - static let jsTemporalPlainDateTimeConstructor = ObjectGroup( + public static let jsTemporalPlainDateTimeConstructor = ObjectGroup( name: "TemporalPlainDateTimeConstructor", constructorPath: "Temporal.PlainDateTime", instanceType: .jsTemporalPlainDateTimeConstructor, properties: [ - "prototype" : jsTemporalPlainDateTimePrototype.instanceType + "prototype": jsTemporalPlainDateTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainDateTime, possibleParams: jsTemporalPlainDateTimeLikeParameters, settingsArg: jsTemporalOverflowSettings), - "compare": temporalCompareSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainDateTime, + possibleParams: jsTemporalPlainDateTimeLikeParameters, + settingsArg: jsTemporalOverflowSettings), + "compare": temporalCompareSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), ] ) - - static let jsTemporalZonedDateTime = ObjectGroup( + public static let jsTemporalZonedDateTime = ObjectGroup( name: "Temporal.ZonedDateTime", instanceType: .jsTemporalZonedDateTime, - properties: mergeFields(jsTemporalPlainDate.properties, jsTemporalPlainTime.properties, [ - "timeZoneId": .string, - "epochMilliseconds": .integer, - "epochNanoseconds": .bigint, - "offsetNanoseconds": .integer, - "offset": .string, - ]), + properties: mergeFields( + jsTemporalPlainDate.properties, jsTemporalPlainTime.properties, + [ + "timeZoneId": .string, + "epochMilliseconds": .integer, + "epochNanoseconds": .bigint, + "offsetNanoseconds": .integer, + "offset": .string, + ]), overloads: [ - "with": [[.plain(jsTemporalZonedDateTimeLikeObjectForWith.instanceType), .opt(jsTemporalZonedInterpretationSettings)] => .jsTemporalZonedDateTime], - "withPlainTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalZonedDateTime}, + "with": [ + [ + .plain(jsTemporalZonedDateTimeLikeObjectForWith.instanceType), + .opt(jsTemporalZonedInterpretationSettings), + ] => .jsTemporalZonedDateTime + ], + "withPlainTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalZonedDateTime + }, "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime], "withTimeZone": [[.string] => .jsTemporalZonedDateTime], - "add": temporalAddSubtractSignature(forType: .jsTemporalZonedDateTime, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalZonedDateTime, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "add": temporalAddSubtractSignature( + forType: .jsTemporalZonedDateTime, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalZonedDateTime, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalZonedDateTime], - "equals": temporalEqualsSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], "startOfDay": [[] => .jsTemporalZonedDateTime], - "getTimeZoneTransition": [[.plain(jsTemporalDirectionParam)] => .jsTemporalZonedDateTime], + "getTimeZoneTransition": [ + [.plain(jsTemporalDirectionParam)] => .jsTemporalZonedDateTime + ], "toInstant": [[] => .jsTemporalInstant], "toPlainDate": [[] => .jsTemporalPlainDate], "toPlainTime": [[] => .jsTemporalPlainTime], @@ -3280,21 +3932,25 @@ public extension ObjectGroup { ] ) - static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup( + public static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup( jsTemporalZonedDateTime, constructor: .jsTemporalZonedDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.ZonedDateTime constructor - static let jsTemporalZonedDateTimeConstructor = ObjectGroup( + public static let jsTemporalZonedDateTimeConstructor = ObjectGroup( name: "TemporalZonedDateTimeConstructor", constructorPath: "Temporal.ZonedDateTime", instanceType: .jsTemporalZonedDateTimeConstructor, properties: [ - "prototype" : jsTemporalZonedDateTimePrototype.instanceType + "prototype": jsTemporalZonedDateTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalZonedDateTime, possibleParams: jsTemporalZonedDateTimeLikeParameters, settingsArg: jsTemporalZonedInterpretationSettings), - "compare": temporalCompareSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalZonedDateTime, + possibleParams: jsTemporalZonedDateTimeLikeParameters, + settingsArg: jsTemporalZonedInterpretationSettings), + "compare": temporalCompareSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), ] ) @@ -3321,33 +3977,33 @@ public extension ObjectGroup { ], methods: [:]) - private static let jsTemporalTimeLikeFields : [String: ILType] = [ - "hour": .number | .undefined, - "minute": .number | .undefined, - "second": .number | .undefined, - "millisecond": .number | .undefined, - "microsecond": .number | .undefined, - "nanosecond": .number | .undefined, + private static let jsTemporalTimeLikeFields: [String: ILType] = [ + "hour": .number | .undefined, + "minute": .number | .undefined, + "second": .number | .undefined, + "millisecond": .number | .undefined, + "microsecond": .number | .undefined, + "nanosecond": .number | .undefined, ] - private static let jsTemporalCalendarField : [String: ILType] = [ - "calendar": .jsTemporalCalendarEnum | .undefined, + private static let jsTemporalCalendarField: [String: ILType] = [ + "calendar": .jsTemporalCalendarEnum | .undefined ] - private static let jsTemporalDateLikeFields : [String: ILType] = [ - "era": .string | .undefined, - "eraYear": .number | .undefined, - "month": .number | .undefined, - "monthCode": .string | .undefined, - "day": .number | .undefined, + private static let jsTemporalDateLikeFields: [String: ILType] = [ + "era": .string | .undefined, + "eraYear": .number | .undefined, + "month": .number | .undefined, + "monthCode": .string | .undefined, + "day": .number | .undefined, ] private static func mergeFields(_ fields: [String: ILType]...) -> [String: ILType] { - fields.reduce([:]) { - $0.merging($1) { _, _ in - fatalError("Duplicate field in \(fields)") + fields.reduce([:]) { + $0.merging($1) { _, _ in + fatalError("Duplicate field in \(fields)") + } } - } } fileprivate static let jsTemporalPlainTimeLikeObject = ObjectGroup( @@ -3365,15 +4021,17 @@ public extension ObjectGroup { fileprivate static let jsTemporalPlainDateTimeLikeObject = ObjectGroup( name: "TemporalPlainDateTimeLikeObject", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, jsTemporalCalendarField), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, jsTemporalCalendarField), methods: [:]) fileprivate static let jsTemporalZonedDateTimeLikeObject = ObjectGroup( name: "TemporalZonedDateTimeLikeObject", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, - ["timeZone": .string | .undefined, "offset": .string | .undefined], - jsTemporalCalendarField), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, + ["timeZone": .string | .undefined, "offset": .string | .undefined], + jsTemporalCalendarField), methods: [:]) // with() takes a reduced set of fields: it cannot have a calendar or timeZone, @@ -3393,38 +4051,68 @@ public extension ObjectGroup { fileprivate static let jsTemporalZonedDateTimeLikeObjectForWith = ObjectGroup( name: "TemporalZonedDateTimeLikeObjectForWith", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, ["offset": .string | .undefined]), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, ["offset": .string | .undefined]), methods: [:]) // Temporal-object-like parameters (accepted by ToTemporalFoo) // ToTemporalFoo, and APIs based on it (from, compare, until, since, equals, occasionally withFoo/toFoo) accept // a Temporal-like object, a Temporal object that is a superset of the type, or a string representation. // TODO(manishearth, 439921647) Most of the stringy types here are with a specific format, we should consider generating them - private static let jsTemporalDurationLikeParameters: [ILType] = [jsTemporalDurationLikeObject.instanceType, .jsTemporalDuration, .string] - private static let jsTemporalInstantLikeParameters: [ILType] = [.jsTemporalInstant, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainTimeLikeParameters: [ILType] = [jsTemporalPlainTimeLikeObject.instanceType, .jsTemporalPlainTime, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainYearMonthLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainYearMonth, .string] - private static let jsTemporalPlainMonthDayLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainMonthDay, .string] - private static let jsTemporalPlainDateLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainDateTimeLikeParameters: [ILType] = [jsTemporalPlainDateTimeLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalZonedDateTimeLikeParameters: [ILType] = [jsTemporalZonedDateTimeLikeObject.instanceType, .string] + private static let jsTemporalDurationLikeParameters: [ILType] = [ + jsTemporalDurationLikeObject.instanceType, .jsTemporalDuration, .string, + ] + private static let jsTemporalInstantLikeParameters: [ILType] = [ + .jsTemporalInstant, .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainTimeLikeParameters: [ILType] = [ + jsTemporalPlainTimeLikeObject.instanceType, .jsTemporalPlainTime, .jsTemporalPlainDateTime, + .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainYearMonthLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainYearMonth, .string, + ] + private static let jsTemporalPlainMonthDayLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainMonthDay, .string, + ] + private static let jsTemporalPlainDateLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, + .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainDateTimeLikeParameters: [ILType] = [ + jsTemporalPlainDateTimeLikeObject.instanceType, .jsTemporalPlainDate, + .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalZonedDateTimeLikeParameters: [ILType] = [ + jsTemporalZonedDateTimeLikeObject.instanceType, .string, + ] // Stringy objects // TODO(manishearth, 439921647) support stringy objects - fileprivate static let jsTemporalTimeZoneLike = ILType.namedString(ofName: "TemporalTimeZoneString") + fileprivate static let jsTemporalTimeZoneLike = ILType.namedString( + ofName: "TemporalTimeZoneString") // Options objects - fileprivate static let jsTemporalDifferenceSettings = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType + fileprivate static let jsTemporalDifferenceSettings = OptionsBag + .jsTemporalDifferenceSettingOrRoundTo.group.instanceType // roundTo accepts a subset of fields compared to differenceSettings; we merge the two bag types but retain separate // variables for clarity in the signatures above. - fileprivate static let jsTemporalRoundTo = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType - fileprivate static let jsTemporalToStringSettings = OptionsBag.jsTemporalToStringSettings.group.instanceType - fileprivate static let jsTemporalOverflowSettings = OptionsBag.jsTemporalOverflowSettings.group.instanceType - fileprivate static let jsTemporalZonedInterpretationSettings = OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType - fileprivate static let jsTemporalDirectionParam = ILType.enumeration(ofName: "directionParam", withValues: ["previous", "next"]) - fileprivate static let jsTemporalDurationRoundToSettings = OptionsBag.jsTemporalDurationRoundToSettings.group.instanceType - fileprivate static let jsTemporalDurationTotalOfSettings = OptionsBag.jsTemporalDurationTotalOfSettings.group.instanceType - fileprivate static let jsTemporalDurationCompareSettings = OptionsBag.jsTemporalDurationCompareSettings.group.instanceType + fileprivate static let jsTemporalRoundTo = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group + .instanceType + fileprivate static let jsTemporalToStringSettings = OptionsBag.jsTemporalToStringSettings.group + .instanceType + fileprivate static let jsTemporalOverflowSettings = OptionsBag.jsTemporalOverflowSettings.group + .instanceType + fileprivate static let jsTemporalZonedInterpretationSettings = OptionsBag + .jsTemporalZonedInterpretationSettings.group.instanceType + fileprivate static let jsTemporalDirectionParam = ILType.enumeration( + ofName: "directionParam", withValues: ["previous", "next"]) + fileprivate static let jsTemporalDurationRoundToSettings = OptionsBag + .jsTemporalDurationRoundToSettings.group.instanceType + fileprivate static let jsTemporalDurationTotalOfSettings = OptionsBag + .jsTemporalDurationTotalOfSettings.group.instanceType + fileprivate static let jsTemporalDurationCompareSettings = OptionsBag + .jsTemporalDurationCompareSettings.group.instanceType // This is huge and comes from Intl, not Temporal // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters fileprivate static let jsTemporalToLocaleStringSettings = ILType.jsAnything @@ -3433,16 +4121,35 @@ public extension ObjectGroup { extension OptionsBag { // Individual enums - fileprivate static let jsTemporalUnitEnum = ILType.enumeration(ofName: "temporalUnit", withValues: ["auto", "year", "month", "week", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "auto", "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]) - fileprivate static let jsTemporalRoundingModeEnum = ILType.enumeration(ofName: "temporalRoundingMode", withValues: ["ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"]) - fileprivate static let jsTemporalShowCalendarEnum = ILType.enumeration(ofName: "temporalShowCalendar", withValues: ["auto", "always", "never", "critical"]) - fileprivate static let jsTemporalShowOffsetEnum = ILType.enumeration(ofName: "temporalShowOffset", withValues: ["auto", "never"]) - fileprivate static let jsTemporalShowTimeZoneEnum = ILType.enumeration(ofName: "temporalShowOfTimeZone", withValues: ["auto", "never", "critical"]) - fileprivate static let jsTemporalOverflowEnum = ILType.enumeration(ofName: "temporalOverflow", withValues: ["constrain", "reject"]) - fileprivate static let jsTemporalDisambiguationEnum = ILType.enumeration(ofName: "temporalDisambiguation", withValues: ["compatible", "earlier", "later", "reject"]) - fileprivate static let jsTemporalOffsetEnum = ILType.enumeration(ofName: "temporalOffset", withValues: ["prefer", "use", "ignore", "reject"]) - - static let jsTemporalRelativeTo = ILType.jsTemporalZonedDateTime | ILType.jsTemporalPlainDateTime | ILType.jsTemporalPlainDate | .string + fileprivate static let jsTemporalUnitEnum = ILType.enumeration( + ofName: "temporalUnit", + withValues: [ + "auto", "year", "month", "week", "day", "hour", "minute", "second", "millisecond", + "microsecond", "nanosecond", "auto", "years", "months", "weeks", "days", "hours", + "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", + ]) + fileprivate static let jsTemporalRoundingModeEnum = ILType.enumeration( + ofName: "temporalRoundingMode", + withValues: [ + "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", + "halfEven", + ]) + fileprivate static let jsTemporalShowCalendarEnum = ILType.enumeration( + ofName: "temporalShowCalendar", withValues: ["auto", "always", "never", "critical"]) + fileprivate static let jsTemporalShowOffsetEnum = ILType.enumeration( + ofName: "temporalShowOffset", withValues: ["auto", "never"]) + fileprivate static let jsTemporalShowTimeZoneEnum = ILType.enumeration( + ofName: "temporalShowOfTimeZone", withValues: ["auto", "never", "critical"]) + fileprivate static let jsTemporalOverflowEnum = ILType.enumeration( + ofName: "temporalOverflow", withValues: ["constrain", "reject"]) + fileprivate static let jsTemporalDisambiguationEnum = ILType.enumeration( + ofName: "temporalDisambiguation", withValues: ["compatible", "earlier", "later", "reject"]) + fileprivate static let jsTemporalOffsetEnum = ILType.enumeration( + ofName: "temporalOffset", withValues: ["prefer", "use", "ignore", "reject"]) + + static let jsTemporalRelativeTo = + ILType.jsTemporalZonedDateTime | ILType.jsTemporalPlainDateTime | ILType.jsTemporalPlainDate + | .string // differenceSettings and roundTo are mostly the same, with differenceSettings accepting an additional largestUnit // note that the Duration roundTo option is different @@ -3471,7 +4178,7 @@ extension OptionsBag { static let jsTemporalOverflowSettings = OptionsBag( name: "jsTemporalOverflowSettingsObject", properties: [ - "overflow": jsTemporalOverflowEnum, + "overflow": jsTemporalOverflowEnum ]) static let jsTemporalZonedInterpretationSettings = OptionsBag( @@ -3482,7 +4189,7 @@ extension OptionsBag { "offset": jsTemporalOffsetEnum, ]) - static let jsTemporalDurationRoundToSettings = OptionsBag( + static let jsTemporalDurationRoundToSettings = OptionsBag( name: "TemporalDurationRoundToSettingsObject", properties: [ "largestUnit": OptionsBag.jsTemporalUnitEnum, @@ -3492,17 +4199,17 @@ extension OptionsBag { "smallestUnit": OptionsBag.jsTemporalUnitEnum, ] ) - static let jsTemporalDurationTotalOfSettings = OptionsBag( + static let jsTemporalDurationTotalOfSettings = OptionsBag( name: "TemporalDurationTotalOfSettingsObject", properties: [ "relativeTo": jsTemporalRelativeTo, "unit": OptionsBag.jsTemporalUnitEnum, ] ) - static let jsTemporalDurationCompareSettings = OptionsBag( + static let jsTemporalDurationCompareSettings = OptionsBag( name: "TemporalDurationCompareSettingsObject", properties: [ - "relativeTo": jsTemporalRelativeTo, + "relativeTo": jsTemporalRelativeTo ] ) @@ -3518,39 +4225,143 @@ extension OptionsBag { // Intl extension ILType { // Intl types - static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "DisplayNames", "DurationFormat", "ListFormat", "Locale", "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter"], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) - - static let jsIntlLocale = ILType.object(ofGroup: "Intl.Locale", withProperties: ["baseName", "calendar", "caseFirst", "collation", "hourCycle", "language", "numberingSystem", "numeric", "region", "script", "variants"], withMethods: ["getCalendars", "getCollations", "getHourCycles", "getNumberingSystems", "getTextInfo", "getTimeZones", "getWeekInfo", "maximize", "minimize", "toString"]) - static let jsIntlLocaleConstructor = ILType.functionAndConstructor([.plain(.jsIntlLocaleString), .opt(OptionsBag.jsIntlLocaleSettings.group.instanceType)] => .jsIntlLocale) + .object(ofGroup: "IntlLocaleConstructor", withProperties: ["prototype"], withMethods: []) - - static let jsIntlCollator = ILType.object(ofGroup: "Intl.Collator", withProperties: [], withMethods: ["compare", "resolvedOptions"]) - static let jsIntlCollatorConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlCollatorSettings.group.instanceType)] => .jsIntlCollator) + .object(ofGroup: "IntlCollatorConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDisplayNames = ILType.object(ofGroup: "Intl.DisplayNames", withProperties: [], withMethods: ["of", "resolvedOptions"]) - static let jsIntlDisplayNamesConstructor = ILType.functionAndConstructor([.plain(.jsIntlLocaleLike), .plain(OptionsBag.jsIntlDisplayNamesSettings.group.instanceType)] => .jsIntlDisplayNames) + .object(ofGroup: "IntlDisplayNamesConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDurationFormat = ILType.object(ofGroup: "Intl.DurationFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlDurationFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDurationFormatSettings.group.instanceType)] => .jsIntlDurationFormat) + .object(ofGroup: "IntlDurationFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDateTimeFormat = ILType.object(ofGroup: "Intl.DateTimeFormat", withProperties: [], withMethods: ["format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions"]) - static let jsIntlDateTimeFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsIntlDateTimeFormat) + .object(ofGroup: "IntlDateTimeFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlListFormat = ILType.object(ofGroup: "Intl.ListFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlListFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlListFormatSettings.group.instanceType)] => .jsIntlListFormat) + .object(ofGroup: "IntlListFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlNumberFormat = ILType.object(ofGroup: "Intl.NumberFormat", withProperties: [], withMethods: ["format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions"]) - static let jsIntlNumberFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlNumberFormatSettings.group.instanceType)] => .jsIntlNumberFormat) + .object(ofGroup: "IntlNumberFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlPluralRules = ILType.object(ofGroup: "Intl.PluralRules", withProperties: [], withMethods: ["select", "selectRange", "resolvedOptions"]) - static let jsIntlPluralRulesConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlPluralRulesSettings.group.instanceType)] => .jsIntlPluralRules) + .object(ofGroup: "IntlPluralRulesConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlRelativeTimeFormat = ILType.object(ofGroup: "Intl.RelativeTimeFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlRelativeTimeFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlRelativeTimeFormatSettings.group.instanceType)] => .jsIntlRelativeTimeFormat) + .object(ofGroup: "IntlRelativeTimeFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlSegmenter = ILType.object(ofGroup: "Intl.Segmenter", withProperties: [], withMethods: ["segment", "resolvedOptions"]) - static let jsIntlSegmenterConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlSegmenterSettings.group.instanceType)] => .jsIntlSegmenter) + .object(ofGroup: "IntlSegmenterConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlSegmenterSegments = ILType.object(ofGroup: "IntlSegmenterSegments", withProperties: [], withMethods: ["containing"]) + static let jsIntlObject = ILType.object( + ofGroup: "Intl", + withProperties: [ + "DateTimeFormat", "Collator", "DisplayNames", "DurationFormat", "ListFormat", "Locale", + "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter", + ], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) + + static let jsIntlLocale = ILType.object( + ofGroup: "Intl.Locale", + withProperties: [ + "baseName", "calendar", "caseFirst", "collation", "hourCycle", "language", + "numberingSystem", "numeric", "region", "script", "variants", + ], + withMethods: [ + "getCalendars", "getCollations", "getHourCycles", "getNumberingSystems", "getTextInfo", + "getTimeZones", "getWeekInfo", "maximize", "minimize", "toString", + ]) + static let jsIntlLocaleConstructor = + ILType.functionAndConstructor( + [.plain(.jsIntlLocaleString), .opt(OptionsBag.jsIntlLocaleSettings.group.instanceType)] + => .jsIntlLocale) + + .object(ofGroup: "IntlLocaleConstructor", withProperties: ["prototype"], withMethods: []) + + static let jsIntlCollator = ILType.object( + ofGroup: "Intl.Collator", withProperties: [], withMethods: ["compare", "resolvedOptions"]) + static let jsIntlCollatorConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlCollatorSettings.group.instanceType)] + => .jsIntlCollator) + + .object( + ofGroup: "IntlCollatorConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDisplayNames = ILType.object( + ofGroup: "Intl.DisplayNames", withProperties: [], withMethods: ["of", "resolvedOptions"]) + static let jsIntlDisplayNamesConstructor = + ILType.functionAndConstructor( + [ + .plain(.jsIntlLocaleLike), + .plain(OptionsBag.jsIntlDisplayNamesSettings.group.instanceType), + ] => .jsIntlDisplayNames) + + .object( + ofGroup: "IntlDisplayNamesConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDurationFormat = ILType.object( + ofGroup: "Intl.DurationFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlDurationFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDurationFormatSettings.group.instanceType), + ] => .jsIntlDurationFormat) + + .object( + ofGroup: "IntlDurationFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDateTimeFormat = ILType.object( + ofGroup: "Intl.DateTimeFormat", withProperties: [], + withMethods: [ + "format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions", + ]) + static let jsIntlDateTimeFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsIntlDateTimeFormat) + + .object( + ofGroup: "IntlDateTimeFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlListFormat = ILType.object( + ofGroup: "Intl.ListFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlListFormatConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlListFormatSettings.group.instanceType)] + => .jsIntlListFormat) + + .object( + ofGroup: "IntlListFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlNumberFormat = ILType.object( + ofGroup: "Intl.NumberFormat", withProperties: [], + withMethods: [ + "format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions", + ]) + static let jsIntlNumberFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlNumberFormatSettings.group.instanceType), + ] => .jsIntlNumberFormat) + + .object( + ofGroup: "IntlNumberFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlPluralRules = ILType.object( + ofGroup: "Intl.PluralRules", withProperties: [], + withMethods: ["select", "selectRange", "resolvedOptions"]) + static let jsIntlPluralRulesConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlPluralRulesSettings.group.instanceType), + ] => .jsIntlPluralRules) + + .object( + ofGroup: "IntlPluralRulesConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlRelativeTimeFormat = ILType.object( + ofGroup: "Intl.RelativeTimeFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlRelativeTimeFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlRelativeTimeFormatSettings.group.instanceType), + ] => .jsIntlRelativeTimeFormat) + + .object( + ofGroup: "IntlRelativeTimeFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlSegmenter = ILType.object( + ofGroup: "Intl.Segmenter", withProperties: [], withMethods: ["segment", "resolvedOptions"]) + static let jsIntlSegmenterConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlSegmenterSettings.group.instanceType)] + => .jsIntlSegmenter) + + .object( + ofGroup: "IntlSegmenterConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlSegmenterSegments = ILType.object( + ofGroup: "IntlSegmenterSegments", withProperties: [], withMethods: ["containing"]) static let jsIntlLocaleString = ILType.namedString(ofName: "IntlLocaleString") static let jsIntlLanguageString = ILType.namedString(ofName: "IntlLanguageString") @@ -3563,22 +4374,24 @@ extension ILType { } extension ObjectGroup { - static let jsIntlSupportedValuesEnum = ILType.enumeration(ofName: "IntlSupportedValues", withValues: ["calendar", "collation", "currency", "numberingSystem", "timeZone"]) + static let jsIntlSupportedValuesEnum = ILType.enumeration( + ofName: "IntlSupportedValues", + withValues: ["calendar", "collation", "currency", "numberingSystem", "timeZone"]) static let jsIntlObject = ObjectGroup( name: "Intl", instanceType: .jsIntlObject, properties: [ - "Collator" : .jsIntlCollatorConstructor, - "DateTimeFormat" : .jsIntlDateTimeFormatConstructor, - "DisplayNames" : .jsIntlDisplayNamesConstructor, - "DurationFormat" : .jsIntlDurationFormatConstructor, - "ListFormat" : .jsIntlListFormatConstructor, - "Locale" : .jsIntlLocaleConstructor, - "NumberFormat" : .jsIntlNumberFormatConstructor, - "PluralRules" : .jsIntlPluralRulesConstructor, - "RelativeTimeFormat" : .jsIntlRelativeTimeFormatConstructor, - "Segmenter" : .jsIntlSegmenterConstructor, + "Collator": .jsIntlCollatorConstructor, + "DateTimeFormat": .jsIntlDateTimeFormatConstructor, + "DisplayNames": .jsIntlDisplayNamesConstructor, + "DurationFormat": .jsIntlDurationFormatConstructor, + "ListFormat": .jsIntlListFormatConstructor, + "Locale": .jsIntlLocaleConstructor, + "NumberFormat": .jsIntlNumberFormatConstructor, + "PluralRules": .jsIntlPluralRulesConstructor, + "RelativeTimeFormat": .jsIntlRelativeTimeFormatConstructor, + "Segmenter": .jsIntlSegmenterConstructor, ], methods: [ "getCanonicalLocales": [] => .jsArray, @@ -3608,11 +4421,14 @@ extension ObjectGroup { constructorPath: "Intl.Collator", instanceType: .jsIntlCollatorConstructor, properties: [ - "prototype" : jsIntlCollatorPrototype.instanceType + "prototype": jsIntlCollatorPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3622,7 +4438,10 @@ extension ObjectGroup { properties: [:], methods: [ "of": [.string] => .string, // TODO(mliedtke): The parameter should be typed more precise than string. - "resolvedOptions": [] => .object(withProperties: ["locale", "style", "type", "fallback", "languageDisplay"]), + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "style", "type", "fallback", "languageDisplay", + ]), ] ) @@ -3635,11 +4454,14 @@ extension ObjectGroup { constructorPath: "Intl.DisplayNames", instanceType: .jsIntlDisplayNamesConstructor, properties: [ - "prototype" : jsIntlDisplayNamesPrototype.instanceType + "prototype": jsIntlDisplayNamesPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3649,8 +4471,12 @@ extension ObjectGroup { properties: [:], methods: [ "format": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] => .string, - "formatToParts": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] => .jsArray, - "resolvedOptions": [] => .object(withProperties: ["locale", "numberingSystem", "style", "fractionalDigits"]), + "formatToParts": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] + => .jsArray, + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "numberingSystem", "style", "fractionalDigits", + ]), ] ) @@ -3663,18 +4489,24 @@ extension ObjectGroup { constructorPath: "Intl.DurationFormat", instanceType: .jsIntlDurationFormatConstructor, properties: [ - "prototype" : jsIntlDurationFormatPrototype.instanceType + "prototype": jsIntlDurationFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) fileprivate static func dateTimeFormatSignature(_ returnType: ILType) -> [Signature] { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format#date // No ZonedDateTime as stated in the docs. - [ILType.jsDate, .jsTemporalPlainDate, .jsTemporalPlainTime, .jsTemporalPlainMonthDay, .jsTemporalPlainYearMonth, .jsTemporalPlainDateTime].map { + [ + ILType.jsDate, .jsTemporalPlainDate, .jsTemporalPlainTime, .jsTemporalPlainMonthDay, + .jsTemporalPlainYearMonth, .jsTemporalPlainDateTime, + ].map { [.opt($0)] => returnType } } @@ -3712,11 +4544,14 @@ extension ObjectGroup { constructorPath: "Intl.DateTimeFormat", instanceType: .jsIntlDateTimeFormatConstructor, properties: [ - "prototype" : jsIntlDateTimeFormatPrototype.instanceType + "prototype": jsIntlDateTimeFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3740,11 +4575,14 @@ extension ObjectGroup { constructorPath: "Intl.ListFormat", instanceType: .jsIntlListFormatConstructor, properties: [ - "prototype" : jsIntlListFormatPrototype.instanceType + "prototype": jsIntlListFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3786,7 +4624,7 @@ extension ObjectGroup { constructorPath: "Intl.Locale", instanceType: .jsIntlLocaleConstructor, properties: [ - "prototype" : jsIntlLocalePrototype.instanceType, + "prototype": jsIntlLocalePrototype.instanceType ], methods: [:] ) @@ -3830,11 +4668,14 @@ extension ObjectGroup { constructorPath: "Intl.NumberFormat", instanceType: .jsIntlNumberFormatConstructor, properties: [ - "prototype" : jsIntlNumberFormatPrototype.instanceType + "prototype": jsIntlNumberFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3857,15 +4698,20 @@ extension ObjectGroup { constructorPath: "Intl.PluralRules", instanceType: .jsIntlPluralRulesConstructor, properties: [ - "prototype" : jsIntlPluralRulesPrototype.instanceType + "prototype": jsIntlPluralRulesPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) - static let jsIntlRelativeTimeFormatUnitEnum = ILType.enumeration(ofName: "IntlRelativeTimeFormatUnit", withValues: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"]) + static let jsIntlRelativeTimeFormatUnitEnum = ILType.enumeration( + ofName: "IntlRelativeTimeFormatUnit", + withValues: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"]) static let jsIntlRelativeTimeFormat = ObjectGroup( name: "Intl.RelativeTimeFormat", @@ -3887,11 +4733,14 @@ extension ObjectGroup { constructorPath: "Intl.RelativeTimeFormat", instanceType: .jsIntlRelativeTimeFormatConstructor, properties: [ - "prototype" : jsIntlRelativeTimeFormatPrototype.instanceType + "prototype": jsIntlRelativeTimeFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3913,11 +4762,14 @@ extension ObjectGroup { constructorPath: "Intl.Segmenter", instanceType: .jsIntlSegmenterConstructor, properties: [ - "prototype" : jsIntlSegmenterPrototype.instanceType + "prototype": jsIntlSegmenterPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) static let jsIntlSegmenterSegments = ObjectGroup( @@ -3925,45 +4777,91 @@ extension ObjectGroup { instanceType: .jsIntlSegmenterSegments, properties: [:], methods: [ - "containing": [.number] => .object(), + "containing": [.number] => .object() ] ) } extension OptionsBag { - fileprivate static let jsIntlLocaleMatcherEnum = ILType.enumeration(ofName: "IntlLocaleMatcher", withValues: ["lookup", "best fit"]) - fileprivate static let jsIntlNumberingSystemEnum = ILType.enumeration(ofName: "IntlNumberingSystem", withValues: Locale.NumberingSystem.availableNumberingSystems.map { $0.identifier }) - fileprivate static let jsIntlHourCycleEnum = ILType.enumeration(ofName: "IntlHourCycle", withValues: ["h11", "h12", "h23", "h24"]) - fileprivate static let jsIntlLongShortNarrowEnum = ILType.enumeration(ofName: "IntlLongShortNarrow", withValues: ["long", "short", "narrow"]) - fileprivate static let jsIntlLongShortEnum = ILType.enumeration(ofName: "IntlLongShort", withValues: ["long", "short"]) - fileprivate static let jsIntlAutoAlwaysEnum = ILType.enumeration(ofName: "IntlAutoAlways", withValues: ["auto", "always"]) - fileprivate static let jsIntlNumeric2DigitEnum = ILType.enumeration(ofName: "IntlNumeric2Digit", withValues: ["numeric", "2-digit"]) - fileprivate static let jsIntlMonthEnum = ILType.enumeration(ofName: "IntlMonth", withValues: ["numeric", "2-digit", "long", "short", "narrow"]) - fileprivate static let jsIntlTimeZoneNameEnum = ILType.enumeration(ofName: "IntlTimeZoneName", withValues: ["long", "short", "shortOffset", "longOffset", "shortGeneric", "longGeneric"]) - fileprivate static let jsIntlFormatMatcherEnum = ILType.enumeration(ofName: "IntlFormatMatcher", withValues: ["basic", "best fit"]) - fileprivate static let jsIntlFullLongMediumShort = ILType.enumeration(ofName: "IntlFullLongMediumShort", withValues: ["full", "long", "medium", "short"]) - fileprivate static let jsIntlCollatorUsageEnum = ILType.enumeration(ofName: "IntlCollatorUsage", withValues: ["sort", "search"]) - fileprivate static let jsIntlCollationEnum = ILType.enumeration(ofName: "IntlCollation", withValues: ["emoji", "pinyin", "stroke"]) - fileprivate static let jsIntlCollationTypeEnum = ILType.enumeration(ofName: "IntlCollationType", withValues: ["compat", "emoji", "eor", "phonebk", "pinyin", "searchjl", "stroke", "trad", "unihan", "zhuyin"]) - fileprivate static let jsIntlCaseFirstEnum = ILType.enumeration(ofName: "IntlCaseFirst", withValues: ["upper", "lower", "false"]) - fileprivate static let jsIntlCollatorSensitivityEnum = ILType.enumeration(ofName: "IntlCollatorSensitivity", withValues: ["base", "accent", "case", "variant"]) - fileprivate static let jsIntlDisplayNamesTypeEnum = ILType.enumeration(ofName: "IntlDisplayNamesTypeEnum", withValues: ["language", "region", "script", "currency", "calendar", "dateTimeField"]) - fileprivate static let jsIntlDisplayNamesFallbackEnum = ILType.enumeration(ofName: "IntlDisplayNamesFallbackEnum", withValues: ["code", "none"]) - fileprivate static let jsIntlDisplayNamesLanguageDisplayEnum = ILType.enumeration(ofName: "IntlDisplayNamesLanguageDisplayEnum", withValues: ["dialect", "standard"]) - fileprivate static let jsIntlDurationFormatStyleEnum = ILType.enumeration(ofName: "IntlDurationFormatStyleEnum", withValues: ["long", "short", "narrow", "digital"]) - fileprivate static let jsIntlListFormatTypeEnum = ILType.enumeration(ofName: "IntlListFormatTypeEnum", withValues: ["conjunction", "disjunction", "unit"]) - fileprivate static let jsIntlNumberFormatStyleEnum = ILType.enumeration(ofName: "IntlNumberFormatStyleEnum", withValues: ["decimal", "currency", "percent", "unit"]) - fileprivate static let jsIntlCurrencySystemEnum = ILType.enumeration(ofName: "IntlCurrency", withValues: Locale.Currency.isoCurrencies.map { $0.identifier }) - fileprivate static let jsIntlCurrencyDisplayEnum = ILType.enumeration(ofName: "IntlCurrencyDisplayEnum", withValues: ["code", "symbol", "narrowSymbol", "name"]) - fileprivate static let jsIntlCurrencySignEnum = ILType.enumeration(ofName: "IntlCurrencySignEnum", withValues: ["standard", "accounting"]) - fileprivate static let jsIntlRoundingPriorityEnum = ILType.enumeration(ofName: "IntlRoundingPriority", withValues: ["auto", "morePrecision", "lessPrecision"]) - fileprivate static let jsIntlRoundingModeEnum = ILType.enumeration(ofName: "IntlRoundingMode", withValues: ["ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"]) - fileprivate static let jsIntlTrailingZeroDisplayEnum = ILType.enumeration(ofName: "IntlTrailingZeroDisplay", withValues: ["auto", "stripIfInteger"]) - fileprivate static let jsIntlNumberFormatNotationEnum = ILType.enumeration(ofName: "IntlNumberFormatNotation", withValues: ["standard", "scientific", "engineering", "compact"]) - fileprivate static let jsIntlNumberFormatGroupingEnum = ILType.enumeration(ofName: "IntlNumberFormatGrouping", withValues: ["always", "auto", "min2", "true", "false"]) - fileprivate static let jsIntlSignDisplayEnum = ILType.enumeration(ofName: "IntlSignDisplay", withValues: ["auto", "always", "exceptZero", "negative", "never"]) - fileprivate static let jsIntlPluralRulesTypeEnum = ILType.enumeration(ofName: "IntlPluralRulesTypeEnum", withValues: ["cardinal", "ordinal"]) - fileprivate static let jsIntlSegmenterGranularityEnum = ILType.enumeration(ofName: "IntlSegmenterGranularityEnum", withValues: ["grapheme", "word", "sentence"]) + fileprivate static let jsIntlLocaleMatcherEnum = ILType.enumeration( + ofName: "IntlLocaleMatcher", withValues: ["lookup", "best fit"]) + fileprivate static let jsIntlNumberingSystemEnum = ILType.enumeration( + ofName: "IntlNumberingSystem", + withValues: Locale.NumberingSystem.availableNumberingSystems.map { $0.identifier }) + fileprivate static let jsIntlHourCycleEnum = ILType.enumeration( + ofName: "IntlHourCycle", withValues: ["h11", "h12", "h23", "h24"]) + fileprivate static let jsIntlLongShortNarrowEnum = ILType.enumeration( + ofName: "IntlLongShortNarrow", withValues: ["long", "short", "narrow"]) + fileprivate static let jsIntlLongShortEnum = ILType.enumeration( + ofName: "IntlLongShort", withValues: ["long", "short"]) + fileprivate static let jsIntlAutoAlwaysEnum = ILType.enumeration( + ofName: "IntlAutoAlways", withValues: ["auto", "always"]) + fileprivate static let jsIntlNumeric2DigitEnum = ILType.enumeration( + ofName: "IntlNumeric2Digit", withValues: ["numeric", "2-digit"]) + fileprivate static let jsIntlMonthEnum = ILType.enumeration( + ofName: "IntlMonth", withValues: ["numeric", "2-digit", "long", "short", "narrow"]) + fileprivate static let jsIntlTimeZoneNameEnum = ILType.enumeration( + ofName: "IntlTimeZoneName", + withValues: ["long", "short", "shortOffset", "longOffset", "shortGeneric", "longGeneric"]) + fileprivate static let jsIntlFormatMatcherEnum = ILType.enumeration( + ofName: "IntlFormatMatcher", withValues: ["basic", "best fit"]) + fileprivate static let jsIntlFullLongMediumShort = ILType.enumeration( + ofName: "IntlFullLongMediumShort", withValues: ["full", "long", "medium", "short"]) + fileprivate static let jsIntlCollatorUsageEnum = ILType.enumeration( + ofName: "IntlCollatorUsage", withValues: ["sort", "search"]) + fileprivate static let jsIntlCollationEnum = ILType.enumeration( + ofName: "IntlCollation", withValues: ["emoji", "pinyin", "stroke"]) + fileprivate static let jsIntlCollationTypeEnum = ILType.enumeration( + ofName: "IntlCollationType", + withValues: [ + "compat", "emoji", "eor", "phonebk", "pinyin", "searchjl", "stroke", "trad", "unihan", + "zhuyin", + ]) + fileprivate static let jsIntlCaseFirstEnum = ILType.enumeration( + ofName: "IntlCaseFirst", withValues: ["upper", "lower", "false"]) + fileprivate static let jsIntlCollatorSensitivityEnum = ILType.enumeration( + ofName: "IntlCollatorSensitivity", withValues: ["base", "accent", "case", "variant"]) + fileprivate static let jsIntlDisplayNamesTypeEnum = ILType.enumeration( + ofName: "IntlDisplayNamesTypeEnum", + withValues: ["language", "region", "script", "currency", "calendar", "dateTimeField"]) + fileprivate static let jsIntlDisplayNamesFallbackEnum = ILType.enumeration( + ofName: "IntlDisplayNamesFallbackEnum", withValues: ["code", "none"]) + fileprivate static let jsIntlDisplayNamesLanguageDisplayEnum = ILType.enumeration( + ofName: "IntlDisplayNamesLanguageDisplayEnum", withValues: ["dialect", "standard"]) + fileprivate static let jsIntlDurationFormatStyleEnum = ILType.enumeration( + ofName: "IntlDurationFormatStyleEnum", withValues: ["long", "short", "narrow", "digital"]) + fileprivate static let jsIntlListFormatTypeEnum = ILType.enumeration( + ofName: "IntlListFormatTypeEnum", withValues: ["conjunction", "disjunction", "unit"]) + fileprivate static let jsIntlNumberFormatStyleEnum = ILType.enumeration( + ofName: "IntlNumberFormatStyleEnum", withValues: ["decimal", "currency", "percent", "unit"]) + fileprivate static let jsIntlCurrencySystemEnum = ILType.enumeration( + ofName: "IntlCurrency", withValues: Locale.Currency.isoCurrencies.map { $0.identifier }) + fileprivate static let jsIntlCurrencyDisplayEnum = ILType.enumeration( + ofName: "IntlCurrencyDisplayEnum", withValues: ["code", "symbol", "narrowSymbol", "name"]) + fileprivate static let jsIntlCurrencySignEnum = ILType.enumeration( + ofName: "IntlCurrencySignEnum", withValues: ["standard", "accounting"]) + fileprivate static let jsIntlRoundingPriorityEnum = ILType.enumeration( + ofName: "IntlRoundingPriority", withValues: ["auto", "morePrecision", "lessPrecision"]) + fileprivate static let jsIntlRoundingModeEnum = ILType.enumeration( + ofName: "IntlRoundingMode", + withValues: [ + "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", + "halfEven", + ]) + fileprivate static let jsIntlTrailingZeroDisplayEnum = ILType.enumeration( + ofName: "IntlTrailingZeroDisplay", withValues: ["auto", "stripIfInteger"]) + fileprivate static let jsIntlNumberFormatNotationEnum = ILType.enumeration( + ofName: "IntlNumberFormatNotation", + withValues: ["standard", "scientific", "engineering", "compact"]) + fileprivate static let jsIntlNumberFormatGroupingEnum = ILType.enumeration( + ofName: "IntlNumberFormatGrouping", withValues: ["always", "auto", "min2", "true", "false"]) + fileprivate static let jsIntlSignDisplayEnum = ILType.enumeration( + ofName: "IntlSignDisplay", + withValues: ["auto", "always", "exceptZero", "negative", "never"]) + fileprivate static let jsIntlPluralRulesTypeEnum = ILType.enumeration( + ofName: "IntlPluralRulesTypeEnum", withValues: ["cardinal", "ordinal"]) + fileprivate static let jsIntlSegmenterGranularityEnum = ILType.enumeration( + ofName: "IntlSegmenterGranularityEnum", withValues: ["grapheme", "word", "sentence"]) // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters static let jsIntlDateTimeFormatSettings = OptionsBag( @@ -3986,7 +4884,7 @@ extension OptionsBag { "hour": jsIntlNumeric2DigitEnum, "minute": jsIntlNumeric2DigitEnum, "second": jsIntlNumeric2DigitEnum, - "fractionalSecondDigits": .integer, // Technically only 1-3 + "fractionalSecondDigits": .integer, // Technically only 1-3 "timeZoneName": jsIntlTimeZoneNameEnum, "formatMatcher": jsIntlFormatMatcherEnum, // style options @@ -4154,14 +5052,15 @@ extension OptionsBag { static let jsIntlLocaleMatcherSettings = OptionsBag( name: "IntlLocaleMatcherSettings", properties: [ - "localeMatcher": jsIntlLocaleMatcherEnum, + "localeMatcher": jsIntlLocaleMatcherEnum ] ) } // Iterator extension OptionsBag { - fileprivate static let jsIteratorZipModeEnum = ILType.enumeration(ofName: "IteratorZipMode", withValues: ["strict", "longest", "shortest"]) + fileprivate static let jsIteratorZipModeEnum = ILType.enumeration( + ofName: "IteratorZipMode", withValues: ["strict", "longest", "shortest"]) static let jsIteratorZipSettings = OptionsBag( name: "IteratorZipSettings", @@ -4177,7 +5076,9 @@ extension OptionsBag { fileprivate static let base64Alphabet = ILType.enumeration(ofName: "base64Alphabet", withValues: ["base64", "base64url"]) fileprivate static let base64LastChunkHandling = - ILType.enumeration(ofName: "base64LastChunkHandling", withValues: ["loose", "strict", "stop-before-partial"]) + ILType.enumeration( + ofName: "base64LastChunkHandling", + withValues: ["loose", "strict", "stop-before-partial"]) static let toBase64Settings = OptionsBag( name: "ToBase64Settings", @@ -4190,7 +5091,7 @@ extension OptionsBag { name: "FromBase64Settings", properties: [ "alphabet": base64Alphabet, - "lastChunkHandling": base64LastChunkHandling + "lastChunkHandling": base64LastChunkHandling, ] ) } diff --git a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift index ed17d6d43..4decc2812 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift @@ -36,7 +36,8 @@ public class CovEdgeSet: ProgramAspects { } public override var description: String { - return "new coverage: \(count) newly discovered edge\(count > 1 ? "s" : "") in the CFG of the target" + return + "new coverage: \(count) newly discovered edge\(count > 1 ? "s" : "") in the CFG of the target" } /// Returns an array of all the newly discovered edges of this CovEdgeSet. @@ -74,14 +75,14 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { /// Whether per-edge hit counts should be tracked as well. /// These are expensive to compute, so this need to be enabled explicitly. - private var shouldTrackEdgeCounts : Bool + private var shouldTrackEdgeCounts: Bool /// Keep track of how often an edge has been reset. Frequently set/cleared edges will be ignored - private var resetCounts : [UInt32:UInt64] = [:] + private var resetCounts: [UInt32: UInt64] = [:] /// How often an edge may be reset at most before it is considered non-deterministic. /// In that case, the edge is marked as found, but will not be considered an aspect of any program. - private let maxResetCount : UInt64 = 1000 + private let maxResetCount: UInt64 = 1000 /// The current edge coverage percentage. public var currentScore: Double { @@ -105,20 +106,19 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { guard libcoverage.cov_initialize(&context) == 0 else { fatalError("Could not initialize libcoverage") } -#if os(Windows) - runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(GetCurrentProcessId())_\(id)") -#else - runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(getpid())_\(id)") -#endif + #if os(Windows) + runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(GetCurrentProcessId())_\(id)") + #else + runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(getpid())_\(id)") + #endif } public func enableEdgeTracking() { - assert(!isInitialized) // This should only be called prior to initialization + assert(!isInitialized) // This should only be called prior to initialization shouldTrackEdgeCounts = true } - public func getEdgeHitCounts() -> [UInt32] { var edgeCounts = libcoverage.edge_counts() let result = libcoverage.cov_get_edge_counts(&context, &edgeCounts) @@ -126,7 +126,8 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { logger.error("Error retrifying smallest hit count edges") return [] } - var edgeArray = Array(UnsafeBufferPointer(start: edgeCounts.edge_hit_count, count: Int(edgeCounts.count))) + var edgeArray = Array( + UnsafeBufferPointer(start: edgeCounts.edge_hit_count, count: Int(edgeCounts.count))) // Clear all edges that have hit their reset limits for (edge, count) in resetCounts { @@ -208,7 +209,9 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { return result == 1 } - public func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + public func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { guard let firstCovEdgeSet = aspects as? CovEdgeSet else { logger.fatal("Coverage Evaluator received non coverage aspects") } @@ -221,8 +224,10 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { guard execution.outcome == .succeeded else { return nil } guard let secondCovEdgeSet = evaluate(execution) as? CovEdgeSet else { return nil } - let firstEdgeSet = Set(UnsafeBufferPointer(start: firstCovEdgeSet.edges, count: Int(firstCovEdgeSet.count))) - let secondEdgeSet = Set(UnsafeBufferPointer(start: secondCovEdgeSet.edges, count: Int(secondCovEdgeSet.count))) + let firstEdgeSet = Set( + UnsafeBufferPointer(start: firstCovEdgeSet.edges, count: Int(firstCovEdgeSet.count))) + let secondEdgeSet = Set( + UnsafeBufferPointer(start: secondCovEdgeSet.edges, count: Int(secondCovEdgeSet.count))) // Reset all edges that were only triggered by the 2nd execution (those only triggered by the 1st execution were already reset earlier). for edge in secondEdgeSet.subtracting(firstEdgeSet) { @@ -252,10 +257,12 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { public func importState(_ state: Data) throws { assert(isInitialized) - let headerSize = 12 // 3 x 4 bytes: num_edges, bitmap_size, found_edges. See exportState() above + let headerSize = 12 // 3 x 4 bytes: num_edges, bitmap_size, found_edges. See exportState() above guard state.count == headerSize + Int(context.bitmap_size) * 2 else { - throw FuzzilliError.evaluatorStateImportError("Cannot import coverage state as it has an unexpected size. Ensure all instances use the same build of the target") + throw FuzzilliError.evaluatorStateImportError( + "Cannot import coverage state as it has an unexpected size. Ensure all instances use the same build of the target" + ) } let numEdges = state.withUnsafeBytes { $0.load(fromByteOffset: 0, as: UInt32.self) } @@ -263,7 +270,9 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { let foundEdges = state.withUnsafeBytes { $0.load(fromByteOffset: 8, as: UInt32.self) } guard bitmapSize == context.bitmap_size && numEdges == context.num_edges else { - throw FuzzilliError.evaluatorStateImportError("Cannot import coverage state due to different bitmap sizes. Ensure all instances use the same build of the target") + throw FuzzilliError.evaluatorStateImportError( + "Cannot import coverage state due to different bitmap sizes. Ensure all instances use the same build of the target" + ) } context.found_edges = foundEdges @@ -281,7 +290,6 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { libcoverage.cov_reset_state(&context) } - // TODO See if we want to count the number of non-deterministic edges and expose them through the fuzzer statistics (if deterministic mode is enabled) private func resetEdge(_ edge: UInt32) { resetCounts[edge] = (resetCounts[edge] ?? 0) + 1 diff --git a/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift index 815f809ef..0d19ccba2 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift @@ -41,7 +41,8 @@ public protocol ProgramEvaluator: Component { /// Executes the program, evaluates the execution, and computes the intersection with the given aspects from a previous execution. /// This will also reset the internal state of the evaluator so that only the aspects common to both program executions are considered already discovered afterwards. - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? /// Resets the internal state func resetState() diff --git a/Sources/Fuzzilli/Execution/Execution.swift b/Sources/Fuzzilli/Execution/Execution.swift index 9297ef296..09a32b7c0 100644 --- a/Sources/Fuzzilli/Execution/Execution.swift +++ b/Sources/Fuzzilli/Execution/Execution.swift @@ -100,19 +100,21 @@ struct DiffExecution: Execution { // TODO(mdanylo): we shouldn't pass dump outputs as a separate parameter, // instead we should rather make them a part of a REPRL protocol between Fuzzilli and V8. - static func diff(optExec: Execution, unoptExec: Execution, - optDumpOut: String, unoptDumpOut: String) -> Execution { + static func diff( + optExec: Execution, unoptExec: Execution, + optDumpOut: String, unoptDumpOut: String + ) -> Execution { assert(optExec.outcome == .succeeded && unoptExec.outcome == .succeeded) func formatDiff(label: String, optData: String, unoptData: String) -> String { return """ - === OPT \(label) === - \(optData) + === OPT \(label) === + \(optData) - === UNOPT \(label) === - \(unoptData) - """ + === UNOPT \(label) === + \(unoptData) + """ } let relateOutcome = DiffOracle.relate(optDumpOut, with: unoptDumpOut) @@ -120,9 +122,12 @@ struct DiffExecution: Execution { return DiffExecution( outcome: relateOutcome ? .succeeded : .differential, execTime: optExec.execTime, - stdout: formatDiff(label: "STDOUT", optData: optExec.stdout, unoptData: unoptExec.stdout), - stderr: formatDiff(label: "STDERR", optData: optExec.stderr, unoptData: unoptExec.stderr), - fuzzout: formatDiff(label: "FUZZOUT", optData: optExec.fuzzout, unoptData: unoptExec.fuzzout) + stdout: formatDiff( + label: "STDOUT", optData: optExec.stdout, unoptData: unoptExec.stdout), + stderr: formatDiff( + label: "STDERR", optData: optExec.stderr, unoptData: unoptExec.stderr), + fuzzout: formatDiff( + label: "FUZZOUT", optData: optExec.fuzzout, unoptData: unoptExec.fuzzout) ) } } diff --git a/Sources/Fuzzilli/Execution/REPRL.swift b/Sources/Fuzzilli/Execution/REPRL.swift index 40555fbd2..44fba010a 100644 --- a/Sources/Fuzzilli/Execution/REPRL.swift +++ b/Sources/Fuzzilli/Execution/REPRL.swift @@ -44,7 +44,10 @@ public class REPRL: ComponentBase, ScriptRunner { /// future executions. This is only used if diagnostics mode is enabled. private var scriptBuffer = String() - public init(executable: String, processArguments: [String], processEnvironment: [String: String], maxExecsBeforeRespawn: Int) { + public init( + executable: String, processArguments: [String], processEnvironment: [String: String], + maxExecsBeforeRespawn: Int + ) { self.processArguments = [executable] + processArguments self.maxExecsBeforeRespawn = maxExecsBeforeRespawn super.init(name: "REPRL") @@ -63,8 +66,12 @@ public class REPRL: ComponentBase, ScriptRunner { let argv = convertToCArray(processArguments) let envp = convertToCArray(env.map({ $0 + "=" + $1 })) - if reprl_initialize_context(reprlContext, argv, envp, /* capture stdout */ 1, /* capture stderr: */ 1) != 0 { - logger.fatal("Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(reprlContext)))") + if reprl_initialize_context( + reprlContext, argv, envp, /* capture stdout */ 1, /* capture stderr: */ 1) != 0 + { + logger.fatal( + "Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(reprlContext)))" + ) } freeCArray(argv, numElems: processArguments.count) @@ -105,28 +112,35 @@ public class REPRL: ComponentBase, ScriptRunner { } } - var execTime: UInt64 = 0 // In microseconds - let timeout = UInt64(timeout) * 1000 // In microseconds + var execTime: UInt64 = 0 // In microseconds + let timeout = UInt64(timeout) * 1000 // In microseconds var status: Int32 = 0 script.withCString { ptr in - status = reprl_execute(reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, freshInstance) + status = reprl_execute( + reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, + freshInstance) // If we fail, we retry after a short timeout and with a fresh instance. If we still fail, we give up trying // to execute this program. If we repeatedly fail to execute any program, we abort. if status < 0 { let errorMsg = String(cString: reprl_get_last_error(reprlContext)) logger.warning("Script execution failed: \(errorMsg). Retrying in 1 second...") if fuzzer.config.enableDiagnostics { - fuzzer.dispatchEvent(fuzzer.events.DiagnosticsEvent, data: (name: "REPRLFail", content: scriptBuffer.data(using: .utf8)!)) + fuzzer.dispatchEvent( + fuzzer.events.DiagnosticsEvent, + data: (name: "REPRLFail", content: scriptBuffer.data(using: .utf8)!)) } Thread.sleep(forTimeInterval: 1) - status = reprl_execute(reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, 1) + status = reprl_execute( + reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, 1) } } if status < 0 { let errorMsg = String(cString: reprl_get_last_error(reprlContext)) - let stderr = String(cString: reprl_fetch_stderr(reprlContext)).trimmingCharacters(in: .whitespacesAndNewlines) - let stdout = String(cString: reprl_fetch_stdout(reprlContext)).trimmingCharacters(in: .whitespacesAndNewlines) + let stderr = String(cString: reprl_fetch_stderr(reprlContext)).trimmingCharacters( + in: .whitespacesAndNewlines) + let stdout = String(cString: reprl_fetch_stdout(reprlContext)).trimmingCharacters( + in: .whitespacesAndNewlines) let childOutput = """ stderr: \(stderr.isEmpty ? "" : stderr) diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index 782f27e11..aabce9662 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -62,7 +62,7 @@ struct DefUseAnalyzer: Analyzer { if isRunning { code.append(instr) } - assert(code[instr.index].op === instr.op) // Must be operating on the program passed in during construction + assert(code[instr.index].op === instr.op) // Must be operating on the program passed in during construction assert(!analysisDone) for v in instr.allOutputs { assignments[v] = [instr.index] @@ -184,16 +184,20 @@ struct ContextAnalyzer: Analyzer { assert(contextStack.count >= 2) // 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. - assert((contextStack.top.contains(.switchBlock) && contextStack.top.subtracting(.switchBlock) == .empty)) + assert( + (contextStack.top.contains(.switchBlock) + && contextStack.top.subtracting(.switchBlock) == .empty)) newContext.formUnion(contextStack.secondToTop) } // If we are in a loop, we don't want to propagate the switch context and vice versa. Otherwise we couldn't determine which break operation to emit. // TODO Make this generic for similar logic cases as well. E.g. by using a instr.op.contextClosed list. - if (instr.op.contextOpened.contains(.switchBlock) || instr.op.contextOpened.contains(.switchCase)) { + if instr.op.contextOpened.contains(.switchBlock) + || instr.op.contextOpened.contains(.switchCase) + { newContext.remove(.loop) - } else if (instr.op.contextOpened.contains(.loop)) { + } else if instr.op.contextOpened.contains(.loop) { newContext.remove(.switchBlock) newContext.remove(.switchCase) } diff --git a/Sources/Fuzzilli/FuzzIL/Blocks.swift b/Sources/Fuzzilli/FuzzIL/Blocks.swift index 7527e440b..4b6d9a518 100644 --- a/Sources/Fuzzilli/FuzzIL/Blocks.swift +++ b/Sources/Fuzzilli/FuzzIL/Blocks.swift @@ -56,7 +56,6 @@ public struct Block { self.tail = tail } - } /// A block group is a sequence of blocks (and thus instructions) that is started by an opening instruction diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index 1e63b0ff9..b0229396c 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -59,7 +59,9 @@ public struct Code: Collection { return instructions[i] } set { - return instructions[i] = Instruction(newValue.op, inouts: newValue.inouts, index: i, flags: newValue.flags) + instructions[i] = Instruction( + newValue.op, inouts: newValue.inouts, index: i, flags: newValue.flags) + return } } @@ -93,12 +95,12 @@ public struct Code: Collection { } /// Returns the instructions in this code in reversed order. - public func reversed() -> ReversedCollection> { + public func reversed() -> ReversedCollection<[Instruction]> { return instructions.reversed() } /// Enumerates the instructions in this code. - public func enumerated() -> EnumeratedSequence> { + public func enumerated() -> EnumeratedSequence<[Instruction]> { return instructions.enumerated() } @@ -182,7 +184,9 @@ public struct Code: Collection { for v in instr.allOutputs { guard !definedVariables.contains(v) else { return false } if v.number > 0 { - guard definedVariables.contains(Variable(number: v.number - 1)) else { return false } + guard definedVariables.contains(Variable(number: v.number - 1)) else { + return false + } } definedVariables.insert(v) } @@ -219,7 +223,8 @@ public struct Code: Collection { if v.number != 0 { let prev = Variable(number: v.number - 1) guard definedVariables.contains(prev) else { - throw FuzzilliError.codeVerificationError("variable definitions are not contiguous: \(v) is defined before \(prev)") + throw FuzzilliError.codeVerificationError( + "variable definitions are not contiguous: \(v) is defined before \(prev)") } } definedVariables[v] = scope @@ -227,7 +232,8 @@ public struct Code: Collection { for (idx, instr) in instructions.enumerated() { guard idx == instr.index else { - throw FuzzilliError.codeVerificationError("instruction \(idx) has wrong index \(String(describing: instr.index))") + throw FuzzilliError.codeVerificationError( + "instruction \(idx) has wrong index \(String(describing: instr.index))") } // Ensure all input variables are valid and have been defined @@ -236,12 +242,14 @@ public struct Code: Collection { throw FuzzilliError.codeVerificationError("variable \(input) was never defined") } guard activeBlocks.contains(where: { $0.scopeId == definingScope }) else { - throw FuzzilliError.codeVerificationError("variable \(input) is not visible anymore") + throw FuzzilliError.codeVerificationError( + "variable \(input) is not visible anymore") } } guard instr.op.requiredContext.isSubset(of: contextAnalyzer.context) else { - throw FuzzilliError.codeVerificationError("operation \(instr.op.name) inside an invalid context") + throw FuzzilliError.codeVerificationError( + "operation \(instr.op.name) inside an invalid context") } // Ensure that the instruction exists in the right context @@ -254,7 +262,8 @@ public struct Code: Collection { } let block = activeBlocks.pop() guard block.head?.isMatchingStart(for: instr.op) ?? false else { - throw FuzzilliError.codeVerificationError("block end does not match block start") + throw FuzzilliError.codeVerificationError( + "block end does not match block start") } } @@ -485,6 +494,8 @@ public struct Code: Collection { /// Check that the given block object describes a block in this code. private func isValidBlock(_ block: Block) -> Bool { - return block.tail <= endIndex && self[block.head].isBlockStart && self[block.tail].isBlockEnd && self[block.tail].op.isMatchingEnd(for: self[block.head].op) + return block.tail <= endIndex && self[block.head].isBlockStart + && self[block.tail].isBlockEnd + && self[block.tail].op.isMatchingEnd(for: self[block.head].op) } } diff --git a/Sources/Fuzzilli/FuzzIL/Context.swift b/Sources/Fuzzilli/FuzzIL/Context.swift index 550610934..080c3d5e8 100644 --- a/Sources/Fuzzilli/FuzzIL/Context.swift +++ b/Sources/Fuzzilli/FuzzIL/Context.swift @@ -39,41 +39,41 @@ public struct Context: OptionSet, Hashable, CaseIterable { } // Default javascript context. - public static let javascript = Context(rawValue: 1 << 0) + public static let javascript = Context(rawValue: 1 << 0) // Inside a subroutine (function, constructor, method, ...) definition. // This for example means that doing `return` or accessing `arguments` is allowed. - public static let subroutine = Context(rawValue: 1 << 1) + public static let subroutine = Context(rawValue: 1 << 1) // Inside a generator function definition. // This for example means that `yield` and `yield*` are allowed. public static let generatorFunction = Context(rawValue: 1 << 2) // Inside an async function definition. // This for example means that `await` is allowed. - public static let asyncFunction = Context(rawValue: 1 << 3) + public static let asyncFunction = Context(rawValue: 1 << 3) // Inside a method. // This for example means that access to `super` is allowed. - public static let method = Context(rawValue: 1 << 4) + public static let method = Context(rawValue: 1 << 4) // Inside a class method. // This for example means that access to private properties is allowed. - public static let classMethod = Context(rawValue: 1 << 5) + public static let classMethod = Context(rawValue: 1 << 5) // Inside a loop. - public static let loop = Context(rawValue: 1 << 6) + public static let loop = Context(rawValue: 1 << 6) // Inside an object literal. - public static let objectLiteral = Context(rawValue: 1 << 7) + public static let objectLiteral = Context(rawValue: 1 << 7) // Inside a class definition. - public static let classDefinition = Context(rawValue: 1 << 8) + public static let classDefinition = Context(rawValue: 1 << 8) // Inside a switch block. - public static let switchBlock = Context(rawValue: 1 << 9) + public static let switchBlock = Context(rawValue: 1 << 9) // Inside a switch case. - public static let switchCase = Context(rawValue: 1 << 10) + public static let switchCase = Context(rawValue: 1 << 10) // Inside a wasm module - public static let wasm = Context(rawValue: 1 << 11) + public static let wasm = Context(rawValue: 1 << 11) // Inside a function in a wasm module - public static let wasmFunction = Context(rawValue: 1 << 12) + public static let wasmFunction = Context(rawValue: 1 << 12) // Inside a wasm recursive type group definition. - public static let wasmTypeGroup = Context(rawValue: 1 << 13) + public static let wasmTypeGroup = Context(rawValue: 1 << 13) + + public static let empty = Context([]) - public static let empty = Context([]) - public var inWasm: Bool { self.contains(.wasm) || self.contains(.wasmFunction) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 35c78eae3..e40947e3b 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -112,12 +112,12 @@ public struct Instruction { /// The output variables of this instruction in the surrounding scope. public var outputs: ArraySlice { - return inouts_[numInputs ..< numInputs + numOutputs] + return inouts_[numInputs.. { - return inouts_[numInputs + numOutputs ..< numInouts] + return inouts_[numInputs + numOutputs.. Variable { @@ -125,12 +125,12 @@ public struct Instruction { } public func innerOutputs(_ r: PartialRangeFrom) -> ArraySlice { - return inouts_[numInputs + numOutputs + r.lowerBound ..< numInouts] + return inouts_[numInputs + numOutputs + r.lowerBound.. { - return inouts_[numInputs ..< numInouts] + return inouts_[numInputs..(_ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags) where Variables.Element == Variable { + public init( + _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags + ) where Variables.Element == Variable { assert(op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count) self.op = op self.inouts_ = Array(inouts) @@ -319,7 +320,8 @@ extension Instruction: ProtobufConvertible { typealias ProtobufType = Fuzzilli_Protobuf_Instruction func asProtobuf(with opCache: OperationCache?) -> ProtobufType { - func convertEnum(_ s: S, _ allValues: [S]) -> P where P.RawValue == Int { + func convertEnum(_ s: S, _ allValues: [S]) -> P + where P.RawValue == Int { return P(rawValue: allValues.firstIndex(of: s)!)! } @@ -338,7 +340,7 @@ extension Instruction: ProtobufConvertible { $0.valueType = Fuzzilli_Protobuf_WasmValueType.nothing } } - if (underlyingWasmType.Is(.wasmFunctionDef())) { + if underlyingWasmType.Is(.wasmFunctionDef()) { return Fuzzilli_Protobuf_WasmILType.with { $0.valueType = Fuzzilli_Protobuf_WasmValueType.functiondef } @@ -381,112 +383,121 @@ extension Instruction: ProtobufConvertible { default: if underlyingWasmType <= .wasmGenericRef { switch underlyingWasmType.wasmReferenceType!.kind { - case .Index(_): - return Fuzzilli_Protobuf_WasmILType.with { - $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { - $0.kind = Fuzzilli_Protobuf_WasmReferenceTypeKind.index - $0.nullability = underlyingWasmType.wasmReferenceType!.nullability - } + case .Index(_): + return Fuzzilli_Protobuf_WasmILType.with { + $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { + $0.kind = Fuzzilli_Protobuf_WasmReferenceTypeKind.index + $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } - case .Abstract(let heapTypeInfo): - let kind = switch heapTypeInfo.heapType { - case .WasmExn: - Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref - case .WasmI31: - Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref - case .WasmFunc: - Fuzzilli_Protobuf_WasmReferenceTypeKind.funcref - case .WasmExtern: - Fuzzilli_Protobuf_WasmReferenceTypeKind.externref - case .WasmAny: - Fuzzilli_Protobuf_WasmReferenceTypeKind.anyref - case .WasmEq: - Fuzzilli_Protobuf_WasmReferenceTypeKind.eqref - case .WasmStruct: - Fuzzilli_Protobuf_WasmReferenceTypeKind.structref - case .WasmArray: - Fuzzilli_Protobuf_WasmReferenceTypeKind.arrayref - case .WasmNone: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noneref - case .WasmNoExtern: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noexternref - case .WasmNoFunc: - Fuzzilli_Protobuf_WasmReferenceTypeKind.nofuncref - case .WasmNoExn: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noexnref + } + case .Abstract(let heapTypeInfo): + let kind = + switch heapTypeInfo.heapType { + case .WasmExn: + Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref + case .WasmI31: + Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref + case .WasmFunc: + Fuzzilli_Protobuf_WasmReferenceTypeKind.funcref + case .WasmExtern: + Fuzzilli_Protobuf_WasmReferenceTypeKind.externref + case .WasmAny: + Fuzzilli_Protobuf_WasmReferenceTypeKind.anyref + case .WasmEq: + Fuzzilli_Protobuf_WasmReferenceTypeKind.eqref + case .WasmStruct: + Fuzzilli_Protobuf_WasmReferenceTypeKind.structref + case .WasmArray: + Fuzzilli_Protobuf_WasmReferenceTypeKind.arrayref + case .WasmNone: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noneref + case .WasmNoExtern: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noexternref + case .WasmNoFunc: + Fuzzilli_Protobuf_WasmReferenceTypeKind.nofuncref + case .WasmNoExn: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noexnref } - return Fuzzilli_Protobuf_WasmILType.with { - $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { - $0.kind = kind - $0.nullability = underlyingWasmType.wasmReferenceType!.nullability - } + return Fuzzilli_Protobuf_WasmILType.with { + $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { + $0.kind = kind + $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } + } } } - fatalError("Can not serialize a non-wasm type \(underlyingWasmType) into a Protobuf_WasmILType! for instruction \(self)") + fatalError( + "Can not serialize a non-wasm type \(underlyingWasmType) into a Protobuf_WasmILType! for instruction \(self)" + ) } } - func convertWasmMemoryLoadType(_ loadType: WasmMemoryLoadType) -> Fuzzilli_Protobuf_WasmMemoryLoadType { + func convertWasmMemoryLoadType(_ loadType: WasmMemoryLoadType) + -> Fuzzilli_Protobuf_WasmMemoryLoadType + { switch loadType { - case .I32LoadMem: - return .i32Loadmem - case .I64LoadMem: - return .i64Loadmem - case .F32LoadMem: - return .f32Loadmem - case .F64LoadMem: - return .f64Loadmem - case .I32LoadMem8S: - return .i32Loadmem8S - case .I32LoadMem8U: - return .i32Loadmem8U - case .I32LoadMem16S: - return .i32Loadmem16S - case .I32LoadMem16U: - return .i32Loadmem16U - case .I64LoadMem8S: - return .i64Loadmem8S - case .I64LoadMem8U: - return .i64Loadmem8U - case .I64LoadMem16S: - return .i64Loadmem16S - case .I64LoadMem16U: - return .i64Loadmem16U - case .I64LoadMem32S: - return .i64Loadmem32S - case .I64LoadMem32U: - return .i64Loadmem32U + case .I32LoadMem: + return .i32Loadmem + case .I64LoadMem: + return .i64Loadmem + case .F32LoadMem: + return .f32Loadmem + case .F64LoadMem: + return .f64Loadmem + case .I32LoadMem8S: + return .i32Loadmem8S + case .I32LoadMem8U: + return .i32Loadmem8U + case .I32LoadMem16S: + return .i32Loadmem16S + case .I32LoadMem16U: + return .i32Loadmem16U + case .I64LoadMem8S: + return .i64Loadmem8S + case .I64LoadMem8U: + return .i64Loadmem8U + case .I64LoadMem16S: + return .i64Loadmem16S + case .I64LoadMem16U: + return .i64Loadmem16U + case .I64LoadMem32S: + return .i64Loadmem32S + case .I64LoadMem32U: + return .i64Loadmem32U } } - func convertWasmMemoryStoreType(_ loadType: WasmMemoryStoreType) -> Fuzzilli_Protobuf_WasmMemoryStoreType { + func convertWasmMemoryStoreType(_ loadType: WasmMemoryStoreType) + -> Fuzzilli_Protobuf_WasmMemoryStoreType + { switch loadType { - case .I32StoreMem: - return .i32Storemem - case .I64StoreMem: - return .i64Storemem - case .F32StoreMem: - return .f32Storemem - case .F64StoreMem: - return .f64Storemem - case .I32StoreMem8: - return .i32Storemem8 - case .I32StoreMem16: - return .i32Storemem16 - case .I64StoreMem8: - return .i64Storemem8 - case .I64StoreMem16: - return .i64Storemem16 - case .I64StoreMem32: - return .i64Storemem32 - case .S128StoreMem: - return .s128Storemem + case .I32StoreMem: + return .i32Storemem + case .I64StoreMem: + return .i64Storemem + case .F32StoreMem: + return .f32Storemem + case .F64StoreMem: + return .f64Storemem + case .I32StoreMem8: + return .i32Storemem8 + case .I32StoreMem16: + return .i32Storemem16 + case .I64StoreMem8: + return .i64Storemem8 + case .I64StoreMem16: + return .i64Storemem16 + case .I64StoreMem32: + return .i64Storemem32 + case .S128StoreMem: + return .s128Storemem } } - func convertWasmGlobal(wasmGlobal: WasmGlobal) -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal { + func convertWasmGlobal(wasmGlobal: WasmGlobal) + -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal + { switch wasmGlobal { case .wasmi32(let val): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.valuei32(val) @@ -499,17 +510,23 @@ extension Instruction: ProtobufConvertible { case .refFunc(let val): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.funcref(Int64(val)) case .externref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.externref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.externref) case .exnref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref) case .i31ref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref) case .imported(let ilType): - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.imported(ILTypeToWasmTypeEnum(ilType)) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.imported( + ILTypeToWasmTypeEnum(ilType)) } } - func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) -> Fuzzilli_Protobuf_WasmCatchKind { + func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) + -> Fuzzilli_Protobuf_WasmCatchKind + { switch catchKind { case .NoRef: return .noRef @@ -550,7 +567,7 @@ extension Instruction: ProtobufConvertible { $0.loadFloat = Fuzzilli_Protobuf_LoadFloat.with { $0.value = op.value } case .loadString(let op): $0.loadString = Fuzzilli_Protobuf_LoadString.with { - $0.value = op.value; + $0.value = op.value if let customName = op.customName { $0.customName = customName } @@ -570,15 +587,23 @@ extension Instruction: ProtobufConvertible { case .loadAsyncDisposableVariable: $0.loadAsyncDisposableVariable = Fuzzilli_Protobuf_LoadAsyncDisposableVariable() case .loadRegExp(let op): - $0.loadRegExp = Fuzzilli_Protobuf_LoadRegExp.with { $0.pattern = op.pattern; $0.flags = op.flags.rawValue } + $0.loadRegExp = Fuzzilli_Protobuf_LoadRegExp.with { + $0.pattern = op.pattern + $0.flags = op.flags.rawValue + } case .beginObjectLiteral: $0.beginObjectLiteral = Fuzzilli_Protobuf_BeginObjectLiteral() case .objectLiteralAddProperty(let op): - $0.objectLiteralAddProperty = Fuzzilli_Protobuf_ObjectLiteralAddProperty.with { $0.propertyName = op.propertyName } + $0.objectLiteralAddProperty = Fuzzilli_Protobuf_ObjectLiteralAddProperty.with { + $0.propertyName = op.propertyName + } case .objectLiteralAddElement(let op): - $0.objectLiteralAddElement = Fuzzilli_Protobuf_ObjectLiteralAddElement.with { $0.index = op.index } + $0.objectLiteralAddElement = Fuzzilli_Protobuf_ObjectLiteralAddElement.with { + $0.index = op.index + } case .objectLiteralAddComputedProperty: - $0.objectLiteralAddComputedProperty = Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty() + $0.objectLiteralAddComputedProperty = + Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty() case .objectLiteralCopyProperties: $0.objectLiteralCopyProperties = Fuzzilli_Protobuf_ObjectLiteralCopyProperties() case .objectLiteralSetPrototype: @@ -591,25 +616,37 @@ extension Instruction: ProtobufConvertible { case .endObjectLiteralMethod: $0.endObjectLiteralMethod = Fuzzilli_Protobuf_EndObjectLiteralMethod() case .beginObjectLiteralComputedMethod(let op): - $0.beginObjectLiteralComputedMethod = Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod.with { $0.parameters = convertParameters(op.parameters) } + $0.beginObjectLiteralComputedMethod = + Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod.with { + $0.parameters = convertParameters(op.parameters) + } case .endObjectLiteralComputedMethod: - $0.endObjectLiteralComputedMethod = Fuzzilli_Protobuf_EndObjectLiteralComputedMethod() + $0.endObjectLiteralComputedMethod = + Fuzzilli_Protobuf_EndObjectLiteralComputedMethod() case .beginObjectLiteralGetter(let op): - $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { $0.propertyName = op.propertyName } + $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { + $0.propertyName = op.propertyName + } case .endObjectLiteralGetter: $0.endObjectLiteralGetter = Fuzzilli_Protobuf_EndObjectLiteralGetter() case .beginObjectLiteralComputedGetter: - $0.beginObjectLiteralComputedGetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + $0.beginObjectLiteralComputedGetter = + Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() case .endObjectLiteralComputedGetter: - $0.endObjectLiteralComputedGetter = Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() + $0.endObjectLiteralComputedGetter = + Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let op): - $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { $0.propertyName = op.propertyName } + $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { + $0.propertyName = op.propertyName + } case .endObjectLiteralSetter: $0.endObjectLiteralSetter = Fuzzilli_Protobuf_EndObjectLiteralSetter() case .beginObjectLiteralComputedSetter: - $0.beginObjectLiteralComputedSetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + $0.beginObjectLiteralComputedSetter = + Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() case .endObjectLiteralComputedSetter: - $0.endObjectLiteralComputedSetter = Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() + $0.endObjectLiteralComputedSetter = + Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() case .endObjectLiteral: $0.endObjectLiteral = Fuzzilli_Protobuf_EndObjectLiteral() case .beginClassDefinition(let op): @@ -618,7 +655,9 @@ extension Instruction: ProtobufConvertible { $0.isExpression = op.isExpression } case .beginClassConstructor(let op): - $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { $0.parameters = convertParameters(op.parameters) } + $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { + $0.parameters = convertParameters(op.parameters) + } case .endClassConstructor: $0.endClassConstructor = Fuzzilli_Protobuf_EndClassConstructor() case .classAddProperty(let op): @@ -669,7 +708,9 @@ extension Instruction: ProtobufConvertible { case .endClassGetter: $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() case .beginClassComputedGetter(let op): - $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { $0.isStatic = op.isStatic } + $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { + $0.isStatic = op.isStatic + } case .endClassComputedGetter: $0.endClassComputedGetter = Fuzzilli_Protobuf_EndClassComputedGetter() case .beginClassSetter(let op): @@ -680,7 +721,9 @@ extension Instruction: ProtobufConvertible { case .endClassSetter: $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() case .beginClassComputedSetter(let op): - $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { $0.isStatic = op.isStatic } + $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { + $0.isStatic = op.isStatic + } case .endClassComputedSetter: $0.endClassComputedSetter = Fuzzilli_Protobuf_EndClassComputedSetter() case .beginClassStaticInitializer: @@ -700,11 +743,17 @@ extension Instruction: ProtobufConvertible { case .createIntArray(let op): $0.createIntArray = Fuzzilli_Protobuf_CreateIntArray.with { $0.values = op.values } case .createFloatArray(let op): - $0.createFloatArray = Fuzzilli_Protobuf_CreateFloatArray.with { $0.values = op.values } + $0.createFloatArray = Fuzzilli_Protobuf_CreateFloatArray.with { + $0.values = op.values + } case .createArrayWithSpread(let op): - $0.createArrayWithSpread = Fuzzilli_Protobuf_CreateArrayWithSpread.with { $0.spreads = op.spreads } + $0.createArrayWithSpread = Fuzzilli_Protobuf_CreateArrayWithSpread.with { + $0.spreads = op.spreads + } case .createTemplateString(let op): - $0.createTemplateString = Fuzzilli_Protobuf_CreateTemplateString.with { $0.parts = op.parts } + $0.createTemplateString = Fuzzilli_Protobuf_CreateTemplateString.with { + $0.parts = op.parts + } case .getProperty(let op): $0.getProperty = Fuzzilli_Protobuf_GetProperty.with { $0.propertyName = op.propertyName @@ -759,13 +808,19 @@ extension Instruction: ProtobufConvertible { $0.type = convertEnum(op.type, PropertyType.allCases) } case .getComputedProperty(let op): - $0.getComputedProperty = Fuzzilli_Protobuf_GetComputedProperty.with { $0.isGuarded = op.isGuarded } + $0.getComputedProperty = Fuzzilli_Protobuf_GetComputedProperty.with { + $0.isGuarded = op.isGuarded + } case .setComputedProperty: $0.setComputedProperty = Fuzzilli_Protobuf_SetComputedProperty() case .updateComputedProperty(let op): - $0.updateComputedProperty = Fuzzilli_Protobuf_UpdateComputedProperty.with{ $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.updateComputedProperty = Fuzzilli_Protobuf_UpdateComputedProperty.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .deleteComputedProperty(let op): - $0.deleteComputedProperty = Fuzzilli_Protobuf_DeleteComputedProperty.with { $0.isGuarded = op.isGuarded } + $0.deleteComputedProperty = Fuzzilli_Protobuf_DeleteComputedProperty.with { + $0.isGuarded = op.isGuarded + } case .configureComputedProperty(let op): $0.configureComputedProperty = Fuzzilli_Protobuf_ConfigureComputedProperty.with { $0.isWritable = op.flags.contains(.writable) @@ -812,7 +867,7 @@ extension Instruction: ProtobufConvertible { $0.name = name } } - case.endAsyncFunction: + case .endAsyncFunction: $0.endAsyncFunction = Fuzzilli_Protobuf_EndAsyncFunction() case .beginAsyncArrowFunction(let op): $0.beginAsyncArrowFunction = Fuzzilli_Protobuf_BeginAsyncArrowFunction.with { @@ -821,7 +876,8 @@ extension Instruction: ProtobufConvertible { case .endAsyncArrowFunction: $0.endAsyncArrowFunction = Fuzzilli_Protobuf_EndAsyncArrowFunction() case .beginAsyncGeneratorFunction(let op): - $0.beginAsyncGeneratorFunction = Fuzzilli_Protobuf_BeginAsyncGeneratorFunction.with { + $0.beginAsyncGeneratorFunction = Fuzzilli_Protobuf_BeginAsyncGeneratorFunction.with + { $0.parameters = convertParameters(op.parameters) if let name = op.functionName { $0.name = name @@ -846,7 +902,9 @@ extension Instruction: ProtobufConvertible { case .await: $0.await = Fuzzilli_Protobuf_Await() case .callFunction(let op): - $0.callFunction = Fuzzilli_Protobuf_CallFunction.with { $0.isGuarded = op.isGuarded } + $0.callFunction = Fuzzilli_Protobuf_CallFunction.with { + $0.isGuarded = op.isGuarded + } case .callFunctionWithSpread(let op): $0.callFunctionWithSpread = Fuzzilli_Protobuf_CallFunctionWithSpread.with { $0.spreads = op.spreads @@ -871,22 +929,31 @@ extension Instruction: ProtobufConvertible { $0.isGuarded = op.isGuarded } case .callComputedMethod(let op): - $0.callComputedMethod = Fuzzilli_Protobuf_CallComputedMethod.with { $0.isGuarded = op.isGuarded } - case .callComputedMethodWithSpread(let op): - $0.callComputedMethodWithSpread = Fuzzilli_Protobuf_CallComputedMethodWithSpread.with { - $0.spreads = op.spreads + $0.callComputedMethod = Fuzzilli_Protobuf_CallComputedMethod.with { $0.isGuarded = op.isGuarded } + case .callComputedMethodWithSpread(let op): + $0.callComputedMethodWithSpread = + Fuzzilli_Protobuf_CallComputedMethodWithSpread.with { + $0.spreads = op.spreads + $0.isGuarded = op.isGuarded + } case .unaryOperation(let op): - $0.unaryOperation = Fuzzilli_Protobuf_UnaryOperation.with { $0.op = convertEnum(op.op, UnaryOperator.allCases) } + $0.unaryOperation = Fuzzilli_Protobuf_UnaryOperation.with { + $0.op = convertEnum(op.op, UnaryOperator.allCases) + } case .binaryOperation(let op): - $0.binaryOperation = Fuzzilli_Protobuf_BinaryOperation.with { $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.binaryOperation = Fuzzilli_Protobuf_BinaryOperation.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .ternaryOperation: $0.ternaryOperation = Fuzzilli_Protobuf_TernaryOperation() case .reassign: $0.reassign = Fuzzilli_Protobuf_Reassign() case .update(let op): - $0.update = Fuzzilli_Protobuf_Update.with { $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.update = Fuzzilli_Protobuf_Update.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .dup: $0.dup = Fuzzilli_Protobuf_Dup() case .destructArray(let op): @@ -910,20 +977,25 @@ extension Instruction: ProtobufConvertible { $0.hasRestElement_p = op.hasRestElement } case .compare(let op): - $0.compare = Fuzzilli_Protobuf_Compare.with { $0.op = convertEnum(op.op, Comparator.allCases) } + $0.compare = Fuzzilli_Protobuf_Compare.with { + $0.op = convertEnum(op.op, Comparator.allCases) + } case .createNamedVariable(let op): $0.createNamedVariable = Fuzzilli_Protobuf_CreateNamedVariable.with { $0.variableName = op.variableName - $0.declarationMode = convertEnum(op.declarationMode, NamedVariableDeclarationMode.allCases) + $0.declarationMode = convertEnum( + op.declarationMode, NamedVariableDeclarationMode.allCases) } case .createNamedDisposableVariable(let op): - $0.createNamedDisposableVariable = Fuzzilli_Protobuf_CreateNamedDisposableVariable.with { - $0.variableName = op.variableName - } + $0.createNamedDisposableVariable = + Fuzzilli_Protobuf_CreateNamedDisposableVariable.with { + $0.variableName = op.variableName + } case .createNamedAsyncDisposableVariable(let op): - $0.createNamedAsyncDisposableVariable = Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable.with { - $0.variableName = op.variableName - } + $0.createNamedAsyncDisposableVariable = + Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable.with { + $0.variableName = op.variableName + } case .eval(let op): $0.eval = Fuzzilli_Protobuf_Eval.with { $0.code = op.code @@ -932,22 +1004,34 @@ extension Instruction: ProtobufConvertible { case .callSuperConstructor: $0.callSuperConstructor = Fuzzilli_Protobuf_CallSuperConstructor() case .callSuperMethod(let op): - $0.callSuperMethod = Fuzzilli_Protobuf_CallSuperMethod.with { $0.methodName = op.methodName } + $0.callSuperMethod = Fuzzilli_Protobuf_CallSuperMethod.with { + $0.methodName = op.methodName + } case .getPrivateProperty(let op): - $0.getPrivateProperty = Fuzzilli_Protobuf_GetPrivateProperty.with { $0.propertyName = op.propertyName } + $0.getPrivateProperty = Fuzzilli_Protobuf_GetPrivateProperty.with { + $0.propertyName = op.propertyName + } case .setPrivateProperty(let op): - $0.setPrivateProperty = Fuzzilli_Protobuf_SetPrivateProperty.with { $0.propertyName = op.propertyName } + $0.setPrivateProperty = Fuzzilli_Protobuf_SetPrivateProperty.with { + $0.propertyName = op.propertyName + } case .updatePrivateProperty(let op): $0.updatePrivateProperty = Fuzzilli_Protobuf_UpdatePrivateProperty.with { $0.propertyName = op.propertyName $0.op = convertEnum(op.op, BinaryOperator.allCases) } case .callPrivateMethod(let op): - $0.callPrivateMethod = Fuzzilli_Protobuf_CallPrivateMethod.with { $0.methodName = op.methodName } + $0.callPrivateMethod = Fuzzilli_Protobuf_CallPrivateMethod.with { + $0.methodName = op.methodName + } case .getSuperProperty(let op): - $0.getSuperProperty = Fuzzilli_Protobuf_GetSuperProperty.with { $0.propertyName = op.propertyName } + $0.getSuperProperty = Fuzzilli_Protobuf_GetSuperProperty.with { + $0.propertyName = op.propertyName + } case .setSuperProperty(let op): - $0.setSuperProperty = Fuzzilli_Protobuf_SetSuperProperty.with { $0.propertyName = op.propertyName } + $0.setSuperProperty = Fuzzilli_Protobuf_SetSuperProperty.with { + $0.propertyName = op.propertyName + } case .getComputedSuperProperty(_): $0.getComputedSuperProperty = Fuzzilli_Protobuf_GetComputedSuperProperty() case .setComputedSuperProperty(_): @@ -992,7 +1076,9 @@ extension Instruction: ProtobufConvertible { case .switchBreak: $0.switchBreak = Fuzzilli_Protobuf_SwitchBreak() case .endSwitchCase(let op): - $0.endSwitchCase = Fuzzilli_Protobuf_EndSwitchCase.with { $0.fallsThrough = op.fallsThrough } + $0.endSwitchCase = Fuzzilli_Protobuf_EndSwitchCase.with { + $0.fallsThrough = op.fallsThrough + } case .endSwitch: $0.endSwitch = Fuzzilli_Protobuf_EndSwitch() case .beginWhileLoopHeader: @@ -1121,13 +1207,21 @@ extension Instruction: ProtobufConvertible { $0.outputCount = Int32(op.outputCount) } case .wasmi32CompareOp(let op): - $0.wasmi32CompareOp = Fuzzilli_Protobuf_Wasmi32CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmi32CompareOp = Fuzzilli_Protobuf_Wasmi32CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmi64CompareOp(let op): - $0.wasmi64CompareOp = Fuzzilli_Protobuf_Wasmi64CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmi64CompareOp = Fuzzilli_Protobuf_Wasmi64CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmf32CompareOp(let op): - $0.wasmf32CompareOp = Fuzzilli_Protobuf_Wasmf32CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmf32CompareOp = Fuzzilli_Protobuf_Wasmf32CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmf64CompareOp(let op): - $0.wasmf64CompareOp = Fuzzilli_Protobuf_Wasmf64CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmf64CompareOp = Fuzzilli_Protobuf_Wasmf64CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmi64BinOp(let op): $0.wasmi64BinOp = Fuzzilli_Protobuf_Wasmi64BinOp.with { $0.op = convertEnum(op.binOpKind, WasmIntegerBinaryOpKind.allCases) @@ -1170,25 +1264,43 @@ extension Instruction: ProtobufConvertible { case .wasmWrapi64Toi32(_): $0.wasmWrapi64Toi32 = Fuzzilli_Protobuf_WasmWrapi64Toi32() case .wasmTruncatef32Toi32(let op): - $0.wasmTruncatef32Toi32 = Fuzzilli_Protobuf_WasmTruncatef32Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef32Toi32 = Fuzzilli_Protobuf_WasmTruncatef32Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef64Toi32(let op): - $0.wasmTruncatef64Toi32 = Fuzzilli_Protobuf_WasmTruncatef64Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef64Toi32 = Fuzzilli_Protobuf_WasmTruncatef64Toi32.with { + $0.isSigned = op.isSigned + } case .wasmExtendi32Toi64(let op): - $0.wasmExtendi32Toi64 = Fuzzilli_Protobuf_WasmExtendi32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmExtendi32Toi64 = Fuzzilli_Protobuf_WasmExtendi32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef32Toi64(let op): - $0.wasmTruncatef32Toi64 = Fuzzilli_Protobuf_WasmTruncatef32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef32Toi64 = Fuzzilli_Protobuf_WasmTruncatef32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef64Toi64(let op): - $0.wasmTruncatef64Toi64 = Fuzzilli_Protobuf_WasmTruncatef64Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef64Toi64 = Fuzzilli_Protobuf_WasmTruncatef64Toi64.with { + $0.isSigned = op.isSigned + } case .wasmConverti32Tof32(let op): - $0.wasmConverti32Tof32 = Fuzzilli_Protobuf_WasmConverti32Tof32.with { $0.isSigned = op.isSigned } + $0.wasmConverti32Tof32 = Fuzzilli_Protobuf_WasmConverti32Tof32.with { + $0.isSigned = op.isSigned + } case .wasmConverti64Tof32(let op): - $0.wasmConverti64Tof32 = Fuzzilli_Protobuf_WasmConverti64Tof32.with { $0.isSigned = op.isSigned } + $0.wasmConverti64Tof32 = Fuzzilli_Protobuf_WasmConverti64Tof32.with { + $0.isSigned = op.isSigned + } case .wasmDemotef64Tof32(_): $0.wasmDemotef64Tof32 = Fuzzilli_Protobuf_WasmDemotef64Tof32() case .wasmConverti32Tof64(let op): - $0.wasmConverti32Tof64 = Fuzzilli_Protobuf_WasmConverti32Tof64.with { $0.isSigned = op.isSigned } + $0.wasmConverti32Tof64 = Fuzzilli_Protobuf_WasmConverti32Tof64.with { + $0.isSigned = op.isSigned + } case .wasmConverti64Tof64(let op): - $0.wasmConverti64Tof64 = Fuzzilli_Protobuf_WasmConverti64Tof64.with { $0.isSigned = op.isSigned } + $0.wasmConverti64Tof64 = Fuzzilli_Protobuf_WasmConverti64Tof64.with { + $0.isSigned = op.isSigned + } case .wasmPromotef32Tof64(_): $0.wasmPromotef32Tof64 = Fuzzilli_Protobuf_WasmPromotef32Tof64() case .wasmReinterpretf32Asi32(_): @@ -1210,15 +1322,23 @@ extension Instruction: ProtobufConvertible { case .wasmSignExtend32Intoi64(_): $0.wasmSignExtend32Intoi64 = Fuzzilli_Protobuf_WasmSignExtend32Intoi64() case .wasmTruncateSatf32Toi32(let op): - $0.wasmTruncateSatf32Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf32Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf64Toi32(let op): - $0.wasmTruncateSatf64Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf64Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf32Toi64(let op): - $0.wasmTruncateSatf32Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf32Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf64Toi64(let op): - $0.wasmTruncateSatf64Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf64Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi64.with { + $0.isSigned = op.isSigned + } - case .wasmReassign(_): + case .wasmReassign(_): $0.wasmReassign = Fuzzilli_Protobuf_WasmReassign() case .wasmDefineGlobal(let op): $0.wasmDefineGlobal = Fuzzilli_Protobuf_WasmDefineGlobal.with { @@ -1299,12 +1419,12 @@ extension Instruction: ProtobufConvertible { } case .wasmMemoryLoad(let op): $0.wasmMemoryLoad = Fuzzilli_Protobuf_WasmMemoryLoad.with { - $0.loadType = convertWasmMemoryLoadType(op.loadType); + $0.loadType = convertWasmMemoryLoadType(op.loadType) $0.staticOffset = op.staticOffset } case .wasmMemoryStore(let op): $0.wasmMemoryStore = Fuzzilli_Protobuf_WasmMemoryStore.with { - $0.storeType = convertWasmMemoryStoreType(op.storeType); + $0.storeType = convertWasmMemoryStoreType(op.storeType) $0.staticOffset = op.staticOffset } case .wasmAtomicLoad(let op): @@ -1441,7 +1561,9 @@ extension Instruction: ProtobufConvertible { case .wasmSelect(_): $0.wasmSelect = Fuzzilli_Protobuf_WasmSelect() case .constSimd128(let op): - $0.constSimd128 = Fuzzilli_Protobuf_ConstSimd128.with { $0.value = op.value.map{ UInt32($0) } } + $0.constSimd128 = Fuzzilli_Protobuf_ConstSimd128.with { + $0.value = op.value.map { UInt32($0) } + } case .wasmSimd128IntegerUnOp(let op): $0.wasmSimd128IntegerUnOp = Fuzzilli_Protobuf_WasmSimd128IntegerUnOp.with { $0.shape = UInt32(op.shape.rawValue) @@ -1453,7 +1575,8 @@ extension Instruction: ProtobufConvertible { $0.binaryOperator = Int32(op.binOpKind.rawValue) } case .wasmSimd128IntegerTernaryOp(let op): - $0.wasmSimd128IntegerTernaryOp = Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp.with { + $0.wasmSimd128IntegerTernaryOp = Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp.with + { $0.shape = UInt32(op.shape.rawValue) $0.opcode = Int32(op.ternaryOpKind.rawValue) } @@ -1513,15 +1636,17 @@ extension Instruction: ProtobufConvertible { case .wasmEndTypeGroup(_): $0.wasmEndTypeGroup = Fuzzilli_Protobuf_WasmEndTypeGroup() case .wasmDefineAdHocSignatureType(let op): - $0.wasmDefineAdHocSignatureType = Fuzzilli_Protobuf_WasmDefineAdHocSignatureType.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) - } + $0.wasmDefineAdHocSignatureType = + Fuzzilli_Protobuf_WasmDefineAdHocSignatureType.with { + $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) + $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + } case .wasmDefineAdHocModuleSignatureType(let op): - $0.wasmDefineAdHocModuleSignatureType = Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) - } + $0.wasmDefineAdHocModuleSignatureType = + Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType.with { + $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) + $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + } case .wasmDefineSignatureType(let op): $0.wasmDefineSignatureType = Fuzzilli_Protobuf_WasmDefineSignatureType.with { $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) @@ -1542,7 +1667,8 @@ extension Instruction: ProtobufConvertible { } } case .wasmDefineForwardOrSelfReference(_): - $0.wasmDefineForwardOrSelfReference = Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference() + $0.wasmDefineForwardOrSelfReference = + Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference() case .wasmResolveForwardReference(_): $0.wasmResolveForwardReference = Fuzzilli_Protobuf_WasmResolveForwardReference() case .wasmArrayNewFixed(_): @@ -1618,9 +1744,11 @@ extension Instruction: ProtobufConvertible { let inouts = proto.inouts.map({ Variable(number: Int($0)) }) // Helper function to convert between the Swift and Protobuf enums. - func convertEnum(_ p: P, _ allValues: [S]) throws -> S where P.RawValue == Int { + func convertEnum(_ p: P, _ allValues: [S]) throws -> S + where P.RawValue == Int { guard allValues.indices.contains(p.rawValue) else { - throw FuzzilliError.instructionDecodingError("invalid enum value \(p.rawValue) for type \(S.self)") + throw FuzzilliError.instructionDecodingError( + "invalid enum value \(p.rawValue) for type \(S.self)") } return allValues[p.rawValue] } @@ -1659,101 +1787,106 @@ extension Instruction: ProtobufConvertible { if wasmType.refType.kind == .index { return .wasmRef(.Index(), nullability: wasmType.refType.nullability) } - let heapType: WasmAbstractHeapType = switch wasmType.refType.kind { - case .externref: - .WasmExtern - case .funcref: - .WasmFunc - case .exnref: - .WasmExn - case .i31Ref: - .WasmI31 - case .anyref: - .WasmAny - case .eqref: - .WasmEq - case .structref: - .WasmStruct - case .arrayref: - .WasmArray - case .noneref: - .WasmNone - case .noexternref: - .WasmNoExtern - case .nofuncref: - .WasmNoFunc - case .noexnref: - .WasmNoExn - case .index: - fatalError("Unexpected index type.") - case .UNRECOGNIZED(let value): - fatalError("Unrecognized wasm reference type \(value)") - } + let heapType: WasmAbstractHeapType = + switch wasmType.refType.kind { + case .externref: + .WasmExtern + case .funcref: + .WasmFunc + case .exnref: + .WasmExn + case .i31Ref: + .WasmI31 + case .anyref: + .WasmAny + case .eqref: + .WasmEq + case .structref: + .WasmStruct + case .arrayref: + .WasmArray + case .noneref: + .WasmNone + case .noexternref: + .WasmNoExtern + case .nofuncref: + .WasmNoFunc + case .noexnref: + .WasmNoExn + case .index: + fatalError("Unexpected index type.") + case .UNRECOGNIZED(let value): + fatalError("Unrecognized wasm reference type \(value)") + } return .wasmRef(heapType, nullability: wasmType.refType.nullability) case .none: fatalError("Absent wasm type") } } - func convertProtoWasmMemoryLoadType(_ loadType: Fuzzilli_Protobuf_WasmMemoryLoadType) -> WasmMemoryLoadType { + func convertProtoWasmMemoryLoadType(_ loadType: Fuzzilli_Protobuf_WasmMemoryLoadType) + -> WasmMemoryLoadType + { switch loadType { - case .i32Loadmem: - return .I32LoadMem - case .i64Loadmem: - return .I64LoadMem - case .f32Loadmem: - return .F32LoadMem - case .f64Loadmem: - return .F64LoadMem - case .i32Loadmem8S: - return .I32LoadMem8S - case .i32Loadmem8U: - return .I32LoadMem8U - case .i32Loadmem16S: - return .I32LoadMem16S - case .i32Loadmem16U: - return .I32LoadMem16U - case .i64Loadmem8S: - return .I64LoadMem8S - case .i64Loadmem8U: - return .I64LoadMem8U - case .i64Loadmem16S: - return .I64LoadMem16S - case .i64Loadmem16U: - return .I64LoadMem16U - case .i64Loadmem32S: - return .I64LoadMem32S - case .i64Loadmem32U: - return .I64LoadMem32U - default: - fatalError("Wrong WasmMemoryLoadType") + case .i32Loadmem: + return .I32LoadMem + case .i64Loadmem: + return .I64LoadMem + case .f32Loadmem: + return .F32LoadMem + case .f64Loadmem: + return .F64LoadMem + case .i32Loadmem8S: + return .I32LoadMem8S + case .i32Loadmem8U: + return .I32LoadMem8U + case .i32Loadmem16S: + return .I32LoadMem16S + case .i32Loadmem16U: + return .I32LoadMem16U + case .i64Loadmem8S: + return .I64LoadMem8S + case .i64Loadmem8U: + return .I64LoadMem8U + case .i64Loadmem16S: + return .I64LoadMem16S + case .i64Loadmem16U: + return .I64LoadMem16U + case .i64Loadmem32S: + return .I64LoadMem32S + case .i64Loadmem32U: + return .I64LoadMem32U + default: + fatalError("Wrong WasmMemoryLoadType") } } - func convertProtoWasmMemoryStoreType(_ loadType: Fuzzilli_Protobuf_WasmMemoryStoreType) -> WasmMemoryStoreType { + func convertProtoWasmMemoryStoreType(_ loadType: Fuzzilli_Protobuf_WasmMemoryStoreType) + -> WasmMemoryStoreType + { switch loadType { - case .i32Storemem: - return .I32StoreMem - case .i64Storemem: - return .I64StoreMem - case .f32Storemem: - return .F32StoreMem - case .f64Storemem: - return .F64StoreMem - case .i32Storemem8: - return .I32StoreMem8 - case .i32Storemem16: - return .I32StoreMem16 - case .i64Storemem8: - return .I64StoreMem8 - case .i64Storemem16: - return .I64StoreMem16 - case .i64Storemem32: - return .I64StoreMem32 - case .s128Storemem: - return .S128StoreMem - default: - fatalError("Wrong WasmMemoryStoreType") + case .i32Storemem: + return .I32StoreMem + case .i64Storemem: + return .I64StoreMem + case .f32Storemem: + return .F32StoreMem + case .f64Storemem: + return .F64StoreMem + case .i32Storemem8: + return .I32StoreMem8 + case .i32Storemem16: + return .I32StoreMem16 + case .i64Storemem8: + return .I64StoreMem8 + case .i64Storemem16: + return .I64StoreMem16 + case .i64Storemem32: + return .I64StoreMem32 + case .s128Storemem: + return .S128StoreMem + default: + fatalError("Wrong WasmMemoryStoreType") } } @@ -1787,18 +1920,20 @@ extension Instruction: ProtobufConvertible { } } - func convertProtoWasmCatchKind(_ catchKind: Fuzzilli_Protobuf_WasmCatchKind) -> WasmBeginTryTable.CatchKind { + func convertProtoWasmCatchKind(_ catchKind: Fuzzilli_Protobuf_WasmCatchKind) + -> WasmBeginTryTable.CatchKind + { switch catchKind { - case .noRef: - return .NoRef - case .ref: - return .Ref - case .allNoRef: - return .AllNoRef - case .allRef: - return .AllRef - case .UNRECOGNIZED(let i): - fatalError("Invalid WasmCatchKind \(i)") + case .noRef: + return .NoRef + case .ref: + return .Ref + case .allNoRef: + return .AllNoRef + case .allRef: + return .AllRef + case .UNRECOGNIZED(let i): + fatalError("Invalid WasmCatchKind \(i)") } } @@ -1807,15 +1942,17 @@ extension Instruction: ProtobufConvertible { } func WasmSignatureFromProto(_ signature: Fuzzilli_Protobuf_WasmSignature) -> WasmSignature { - return WasmSignature(expects: signature.parameterTypes.map(WasmTypeEnumToILType), - returns: signature.outputTypes.map(WasmTypeEnumToILType)) + return WasmSignature( + expects: signature.parameterTypes.map(WasmTypeEnumToILType), + returns: signature.outputTypes.map(WasmTypeEnumToILType)) } let op: Operation switch operation { case .opIdx(let idx): guard let cachedOp = opCache?.get(Int(idx)) else { - throw FuzzilliError.instructionDecodingError("invalid operation index or no decoding context available") + throw FuzzilliError.instructionDecodingError( + "invalid operation index or no decoding context available") } op = cachedOp case .loadInteger(let p): @@ -1825,7 +1962,7 @@ extension Instruction: ProtobufConvertible { case .loadFloat(let p): op = LoadFloat(value: p.value) case .loadString(let p): - let customName = p.customName.isEmpty ? nil: p.customName; + let customName = p.customName.isEmpty ? nil : p.customName op = LoadString(value: p.value, customName: customName) case .loadBoolean(let p): op = LoadBoolean(value: p.value) @@ -1856,7 +1993,8 @@ extension Instruction: ProtobufConvertible { case .objectLiteralSetPrototype: op = ObjectLiteralSetPrototype() case .beginObjectLiteralMethod(let p): - op = BeginObjectLiteralMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) + op = BeginObjectLiteralMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters)) case .endObjectLiteralMethod: op = EndObjectLiteralMethod() case .beginObjectLiteralComputedMethod(let p): @@ -1882,23 +2020,28 @@ extension Instruction: ProtobufConvertible { case .endObjectLiteral: op = EndObjectLiteral() case .beginClassDefinition(let p): - op = BeginClassDefinition(hasSuperclass: p.hasSuperclass_p, isExpression: p.isExpression) + op = BeginClassDefinition( + hasSuperclass: p.hasSuperclass_p, isExpression: p.isExpression) case .beginClassConstructor(let p): op = BeginClassConstructor(parameters: convertParameters(p.parameters)) case .endClassConstructor: op = EndClassConstructor() case .classAddProperty(let p): - op = ClassAddProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + op = ClassAddProperty( + propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) case .classAddElement(let p): op = ClassAddElement(index: p.index, hasValue: p.hasValue_p, isStatic: p.isStatic) case .classAddComputedProperty(let p): op = ClassAddComputedProperty(hasValue: p.hasValue_p, isStatic: p.isStatic) case .beginClassMethod(let p): - op = BeginClassMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters), + isStatic: p.isStatic) case .endClassMethod: op = EndClassMethod() case .beginClassComputedMethod(let p): - op = BeginClassComputedMethod(parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassComputedMethod( + parameters: convertParameters(p.parameters), isStatic: p.isStatic) case .endClassComputedMethod: op = EndClassComputedMethod() case .beginClassGetter(let p): @@ -1922,9 +2065,12 @@ extension Instruction: ProtobufConvertible { case .endClassStaticInitializer: op = EndClassStaticInitializer() case .classAddPrivateProperty(let p): - op = ClassAddPrivateProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + op = ClassAddPrivateProperty( + propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) case .beginClassPrivateMethod(let p): - op = BeginClassPrivateMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassPrivateMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters), + isStatic: p.isStatic) case .endClassPrivateMethod: op = EndClassPrivateMethod() case .endClassDefinition: @@ -1944,7 +2090,9 @@ extension Instruction: ProtobufConvertible { case .setProperty(let p): op = SetProperty(propertyName: p.propertyName, isGuarded: p.isGuarded) case .updateProperty(let p): - op = UpdateProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .deleteProperty(let p): op = DeleteProperty(propertyName: p.propertyName, isGuarded: p.isGuarded) case .configureProperty(let p): @@ -1952,13 +2100,16 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureProperty(propertyName: p.propertyName, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureProperty( + propertyName: p.propertyName, flags: flags, + type: try convertEnum(p.type, PropertyType.allCases)) case .getElement(let p): op = GetElement(index: p.index, isGuarded: p.isGuarded) case .setElement(let p): op = SetElement(index: p.index) case .updateElement(let p): - op = UpdateElement(index: p.index, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateElement( + index: p.index, operator: try convertEnum(p.op, BinaryOperator.allCases)) case .deleteElement(let p): op = DeleteElement(index: p.index, isGuarded: p.isGuarded) case .configureElement(let p): @@ -1966,7 +2117,8 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureElement(index: p.index, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureElement( + index: p.index, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) case .getComputedProperty(let p): op = GetComputedProperty(isGuarded: p.isGuarded) case .setComputedProperty: @@ -1980,7 +2132,8 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureComputedProperty(flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureComputedProperty( + flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) case .typeOf: op = TypeOf() case .void: @@ -2043,19 +2196,25 @@ extension Instruction: ProtobufConvertible { case .callFunction(let p): op = CallFunction(numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .callFunctionWithSpread(let p): - op = CallFunctionWithSpread(numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallFunctionWithSpread( + numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) case .construct(let p): op = Construct(numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .constructWithSpread(let p): - op = ConstructWithSpread(numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = ConstructWithSpread( + numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) case .callMethod(let p): - op = CallMethod(methodName: p.methodName, numArguments: inouts.count - 2, isGuarded: p.isGuarded) + op = CallMethod( + methodName: p.methodName, numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .callMethodWithSpread(let p): - op = CallMethodWithSpread(methodName: p.methodName, numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallMethodWithSpread( + methodName: p.methodName, numArguments: inouts.count - 2, spreads: p.spreads, + isGuarded: p.isGuarded) case .callComputedMethod(let p): op = CallComputedMethod(numArguments: inouts.count - 3, isGuarded: p.isGuarded) case .callComputedMethodWithSpread(let p): - op = CallComputedMethodWithSpread(numArguments: inouts.count - 3, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallComputedMethodWithSpread( + numArguments: inouts.count - 3, spreads: p.spreads, isGuarded: p.isGuarded) case .unaryOperation(let p): op = UnaryOperation(try convertEnum(p.op, UnaryOperator.allCases)) case .binaryOperation(let p): @@ -2071,15 +2230,20 @@ extension Instruction: ProtobufConvertible { case .destructArray(let p): op = DestructArray(indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) case .destructArrayAndReassign(let p): - op = DestructArrayAndReassign(indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) + op = DestructArrayAndReassign( + indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) case .destructObject(let p): op = DestructObject(properties: p.properties, hasRestElement: p.hasRestElement_p) case .destructObjectAndReassign(let p): - op = DestructObjectAndReassign(properties: p.properties, hasRestElement: p.hasRestElement_p) + op = DestructObjectAndReassign( + properties: p.properties, hasRestElement: p.hasRestElement_p) case .compare(let p): op = Compare(try convertEnum(p.op, Comparator.allCases)) case .createNamedVariable(let p): - op = CreateNamedVariable(p.variableName, declarationMode: try convertEnum(p.declarationMode, NamedVariableDeclarationMode.allCases)) + op = CreateNamedVariable( + p.variableName, + declarationMode: try convertEnum( + p.declarationMode, NamedVariableDeclarationMode.allCases)) case .createNamedDisposableVariable(let p): op = CreateNamedDisposableVariable(p.variableName) case .createNamedAsyncDisposableVariable(let p): @@ -2096,7 +2260,9 @@ extension Instruction: ProtobufConvertible { case .setPrivateProperty(let p): op = SetPrivateProperty(propertyName: p.propertyName) case .updatePrivateProperty(let p): - op = UpdatePrivateProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdatePrivateProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .callPrivateMethod(let p): op = CallPrivateMethod(methodName: p.methodName, numArguments: inouts.count - 2) case .getSuperProperty(let p): @@ -2108,13 +2274,17 @@ extension Instruction: ProtobufConvertible { case .setComputedSuperProperty(_): op = SetComputedSuperProperty() case .updateSuperProperty(let p): - op = UpdateSuperProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateSuperProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .explore(let p): op = Explore(id: p.id, numArguments: inouts.count - 1, rngSeed: UInt32(p.rngSeed)) case .probe(let p): op = Probe(id: p.id) case .fixup(let p): - op = Fixup(id: p.id, action: p.action, originalOperation: p.originalOperation, numArguments: inouts.count - (p.hasOutput_p ? 1 : 0), hasOutput: p.hasOutput_p) + op = Fixup( + id: p.id, action: p.action, originalOperation: p.originalOperation, + numArguments: inouts.count - (p.hasOutput_p ? 1 : 0), hasOutput: p.hasOutput_p) case .beginWith: op = BeginWith() case .endWith: @@ -2168,11 +2338,13 @@ extension Instruction: ProtobufConvertible { case .beginForOfLoop: op = BeginForOfLoop() case .beginForOfLoopWithDestruct(let p): - op = BeginForOfLoopWithDestruct(indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) + op = BeginForOfLoopWithDestruct( + indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) case .endForOfLoop: op = EndForOfLoop() case .beginRepeatLoop(let p): - op = BeginRepeatLoop(iterations: Int(p.iterations), exposesLoopCounter: p.exposesLoopCounter) + op = BeginRepeatLoop( + iterations: Int(p.iterations), exposesLoopCounter: p.exposesLoopCounter) case .endRepeatLoop: op = EndRepeatLoop() case .loopBreak: @@ -2202,10 +2374,13 @@ extension Instruction: ProtobufConvertible { case .nop: op = Nop() case .createWasmGlobal(let p): - op = CreateWasmGlobal(value: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) + op = CreateWasmGlobal( + value: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) case .createWasmMemory(let p): let maxPages = p.wasmMemory.hasMaxPages ? Int(p.wasmMemory.maxPages) : nil - op = CreateWasmMemory(limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) + op = CreateWasmMemory( + limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), + isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) case .createWasmTable(let p): let maxSize: Int? if p.hasMaxSize { @@ -2213,7 +2388,9 @@ extension Instruction: ProtobufConvertible { } else { maxSize = nil } - op = CreateWasmTable(elementType: WasmTypeEnumToILType(p.elementType), limits: Limits(min: Int(p.minSize), max: maxSize), isTable64: p.isTable64) + op = CreateWasmTable( + elementType: WasmTypeEnumToILType(p.elementType), + limits: Limits(min: Int(p.minSize), max: maxSize), isTable64: p.isTable64) case .createWasmJstag(_): op = CreateWasmJSTag() case .createWasmTag(let p): @@ -2249,13 +2426,17 @@ extension Instruction: ProtobufConvertible { // Wasm Numerical Operations case .wasmi32CompareOp(let p): - op = Wasmi32CompareOp(compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmi32CompareOp( + compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmi64CompareOp(let p): - op = Wasmi64CompareOp(compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmi64CompareOp( + compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmf32CompareOp(let p): - op = Wasmf32CompareOp(compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmf32CompareOp( + compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmf64CompareOp(let p): - op = Wasmf64CompareOp(compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmf64CompareOp( + compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmi32EqualZero(_): op = Wasmi32EqualZero() case .wasmi64EqualZero(_): @@ -2333,14 +2514,18 @@ extension Instruction: ProtobufConvertible { case .wasmReassign(_): op = WasmReassign() case .wasmDefineGlobal(let p): - op = WasmDefineGlobal(wasmGlobal: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) + op = WasmDefineGlobal( + wasmGlobal: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) case .wasmDefineTable(let p): - op = WasmDefineTable(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), - definedEntries: p.definedEntries.map { entry in - WasmTableType.IndexInTableAndWasmSignature(indexInTable: Int(entry.index), signature: WasmSignatureFromProto(entry.signature)) - }, - isTable64: p.isTable64) + op = WasmDefineTable( + elementType: WasmTypeEnumToILType(p.elementType), + limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), + definedEntries: p.definedEntries.map { entry in + WasmTableType.IndexInTableAndWasmSignature( + indexInTable: Int(entry.index), + signature: WasmSignatureFromProto(entry.signature)) + }, + isTable64: p.isTable64) case .wasmDefineElementSegment(let p): op = WasmDefineElementSegment(size: p.size) case .wasmDropElementSegment(_): @@ -2351,7 +2536,9 @@ extension Instruction: ProtobufConvertible { op = WasmTableCopy() case .wasmDefineMemory(let p): let maxPages = p.wasmMemory.hasMaxPages ? Int(p.wasmMemory.maxPages) : nil - op = WasmDefineMemory(limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) + op = WasmDefineMemory( + limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), + isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) case .wasmDefineDataSegment(let p): op = WasmDefineDataSegment(segment: [UInt8](p.segment)) case .wasmLoadGlobal(let p): @@ -2367,7 +2554,8 @@ extension Instruction: ProtobufConvertible { let outputs = p.outputTypes.map(WasmTypeEnumToILType) op = WasmCallIndirect(signature: parameters => outputs) case .wasmCallDirect(let p): - op = WasmCallDirect(parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) + op = WasmCallDirect( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmReturnCallDirect(let p): op = WasmReturnCallDirect(parameterCount: Int(p.parameterCount)) case .wasmReturnCallIndirect(let p): @@ -2375,9 +2563,12 @@ extension Instruction: ProtobufConvertible { let outputs = p.outputTypes.map(WasmTypeEnumToILType) op = WasmReturnCallIndirect(signature: parameters => outputs) case .wasmMemoryLoad(let p): - op = WasmMemoryLoad(loadType: convertProtoWasmMemoryLoadType(p.loadType), staticOffset: p.staticOffset) + op = WasmMemoryLoad( + loadType: convertProtoWasmMemoryLoadType(p.loadType), staticOffset: p.staticOffset) case .wasmMemoryStore(let p): - op = WasmMemoryStore(storeType: convertProtoWasmMemoryStoreType(p.storeType), staticOffset: p.staticOffset) + op = WasmMemoryStore( + storeType: convertProtoWasmMemoryStoreType(p.storeType), + staticOffset: p.staticOffset) case .wasmMemorySize(_): op = WasmMemorySize() case .wasmMemoryGrow(_): @@ -2416,8 +2607,9 @@ extension Instruction: ProtobufConvertible { case .wasmBeginCatchAll(let p): op = WasmBeginCatchAll(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginCatch(let p): - op = WasmBeginCatch(blockOutputCount: Int(p.blockOutputCount), - labelParameterCount: Int(p.labelParameterCount)) + op = WasmBeginCatch( + blockOutputCount: Int(p.blockOutputCount), + labelParameterCount: Int(p.labelParameterCount)) case .wasmEndTry(let p): op = WasmEndTry(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginTryDelegate(let p): @@ -2435,13 +2627,19 @@ extension Instruction: ProtobufConvertible { case .wasmBranch(_): op = WasmBranch(parameterCount: inouts.count - 1) case .wasmBranchIf(let p): - op = WasmBranchIf(parameterCount: inouts.count - 2, hint: try convertEnum(p.hint, WasmBranchHint.allCases)) + op = WasmBranchIf( + parameterCount: inouts.count - 2, + hint: try convertEnum(p.hint, WasmBranchHint.allCases)) case .wasmBranchTable(let p): - op = WasmBranchTable(parameterCount: inouts.count - Int(p.valueCount) - 2, valueCount: Int(p.valueCount)) + op = WasmBranchTable( + parameterCount: inouts.count - Int(p.valueCount) - 2, valueCount: Int(p.valueCount)) case .wasmBeginIf(let p): - op = WasmBeginIf(parameterCount: Int(p.parameterCount), hint: try convertEnum(p.hint, WasmBranchHint.allCases), inverted: p.inverted) + op = WasmBeginIf( + parameterCount: Int(p.parameterCount), + hint: try convertEnum(p.hint, WasmBranchHint.allCases), inverted: p.inverted) case .wasmBeginElse(let p): - op = WasmBeginElse(parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) + op = WasmBeginElse( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmEndIf(let p): op = WasmEndIf(outputCount: Int(p.outputCount)) case .wasmNop(_): @@ -2451,7 +2649,7 @@ extension Instruction: ProtobufConvertible { case .wasmSelect(_): op = WasmSelect() case .constSimd128(let p): - op = ConstSimd128(value: p.value.map{ UInt8($0) }) + op = ConstSimd128(value: p.value.map { UInt8($0) }) case .wasmSimd128IntegerUnOp(let p): let shape = WasmSimd128Shape(rawValue: UInt8(p.shape))! let unOpKind = WasmSimd128IntegerUnOpKind(rawValue: Int(p.unaryOperator))! @@ -2478,41 +2676,61 @@ extension Instruction: ProtobufConvertible { op = WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: ternaryOpKind) case .wasmSimd128Compare(let p): let shape = WasmSimd128Shape(rawValue: UInt8(p.shape))! - let compareOpKind = if shape.isFloat() { - WasmSimd128CompareOpKind.fKind(value: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) - } else { - WasmSimd128CompareOpKind.iKind(value: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) - } + let compareOpKind = + if shape.isFloat() { + WasmSimd128CompareOpKind.fKind( + value: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + } else { + WasmSimd128CompareOpKind.iKind( + value: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + } op = WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind) case .wasmSimdSplat(let p): op = WasmSimdSplat(try convertEnum(p.kind, WasmSimdSplat.Kind.allCases)) case .wasmSimdExtractLane(let p): - op = WasmSimdExtractLane(kind: try convertEnum(p.kind, WasmSimdExtractLane.Kind.allCases), lane: Int(p.lane)) + op = WasmSimdExtractLane( + kind: try convertEnum(p.kind, WasmSimdExtractLane.Kind.allCases), lane: Int(p.lane)) case .wasmSimdReplaceLane(let p): - op = WasmSimdReplaceLane(kind: try convertEnum(p.kind, WasmSimdReplaceLane.Kind.allCases), lane: Int(p.lane)) + op = WasmSimdReplaceLane( + kind: try convertEnum(p.kind, WasmSimdReplaceLane.Kind.allCases), lane: Int(p.lane)) case .wasmSimdLoad(let p): - op = WasmSimdLoad(kind: try convertEnum(p.kind, WasmSimdLoad.Kind.allCases), staticOffset: p.staticOffset) + op = WasmSimdLoad( + kind: try convertEnum(p.kind, WasmSimdLoad.Kind.allCases), + staticOffset: p.staticOffset) case .wasmSimdLoadLane(let p): - op = WasmSimdLoadLane(kind: try convertEnum(p.kind, WasmSimdLoadLane.Kind.allCases), staticOffset: p.staticOffset, lane: Int(p.lane)) + op = WasmSimdLoadLane( + kind: try convertEnum(p.kind, WasmSimdLoadLane.Kind.allCases), + staticOffset: p.staticOffset, lane: Int(p.lane)) case .wasmSimdStoreLane(let p): - op = WasmSimdStoreLane(kind: try convertEnum(p.kind, WasmSimdStoreLane.Kind.allCases), staticOffset: p.staticOffset, lane: Int(p.lane)) + op = WasmSimdStoreLane( + kind: try convertEnum(p.kind, WasmSimdStoreLane.Kind.allCases), + staticOffset: p.staticOffset, lane: Int(p.lane)) case .wasmBeginTypeGroup(_): op = WasmBeginTypeGroup() case .wasmEndTypeGroup(_): assert(inouts.count % 2 == 0) op = WasmEndTypeGroup(typesCount: inouts.count / 2) case .wasmDefineArrayType(let p): - op = WasmDefineArrayType(elementType: WasmTypeEnumToILType(p.elementType), mutability: p.mutability) + op = WasmDefineArrayType( + elementType: WasmTypeEnumToILType(p.elementType), mutability: p.mutability) case .wasmDefineSignatureType(let p): - op = WasmDefineSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineAdHocSignatureType(let p): - op = WasmDefineAdHocSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineAdHocSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineAdHocModuleSignatureType(let p): - op = WasmDefineAdHocModuleSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineAdHocModuleSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineStructType(let p): - op = WasmDefineStructType(fields: p.fields.map { field in - return WasmDefineStructType.Field(type: WasmTypeEnumToILType(field.type), mutability: field.mutability) - }) + op = WasmDefineStructType( + fields: p.fields.map { field in + return WasmDefineStructType.Field( + type: WasmTypeEnumToILType(field.type), mutability: field.mutability) + }) case .wasmDefineForwardOrSelfReference(_): op = WasmDefineForwardOrSelfReference() case .wasmResolveForwardReference(_): @@ -2536,7 +2754,8 @@ extension Instruction: ProtobufConvertible { case .wasmStructSet(let p): op = WasmStructSet(fieldIndex: Int(p.fieldIndex)) case .wasmRefNull(let p): - op = p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) + op = + p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) case .wasmRefIsNull(_): op = WasmRefIsNull() case .wasmRefEq(_): @@ -2550,13 +2769,19 @@ extension Instruction: ProtobufConvertible { case .wasmI31Get(let p): op = WasmI31Get(isSigned: p.isSigned) case .wasmAtomicLoad(let p): - op = WasmAtomicLoad(loadType: try convertEnum(p.loadType, WasmAtomicLoadType.allCases), offset: p.offset) + op = WasmAtomicLoad( + loadType: try convertEnum(p.loadType, WasmAtomicLoadType.allCases), offset: p.offset + ) case .wasmAtomicStore(let p): - op = WasmAtomicStore(storeType: try convertEnum(p.storeType, WasmAtomicStoreType.allCases), offset: p.offset) + op = WasmAtomicStore( + storeType: try convertEnum(p.storeType, WasmAtomicStoreType.allCases), + offset: p.offset) case .wasmAtomicRmw(let p): - op = WasmAtomicRMW(op: try convertEnum(p.op, WasmAtomicRMWType.allCases), offset: p.offset) + op = WasmAtomicRMW( + op: try convertEnum(p.op, WasmAtomicRMWType.allCases), offset: p.offset) case .wasmAtomicCmpxchg(let p): - op = WasmAtomicCmpxchg(op: try convertEnum(p.op, WasmAtomicCmpxchgType.allCases), offset: p.offset) + op = WasmAtomicCmpxchg( + op: try convertEnum(p.op, WasmAtomicCmpxchgType.allCases), offset: p.offset) case .wasmAnyConvertExtern(_): op = WasmAnyConvertExtern() case .wasmExternConvertAny(_): @@ -2564,7 +2789,8 @@ extension Instruction: ProtobufConvertible { } guard op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count else { - throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs for operation \(op)") + throw FuzzilliError.instructionDecodingError( + "incorrect number of in- and outputs for operation \(op)") } opCache?.add(op) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 8b55de0a5..8c49dcc19 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -35,11 +35,11 @@ public struct JSTyper: Analyzer { private var typeGroups: [[Variable]] = [] // Tracks the direct and transitive dependencies of each type group index to the respective // type group indices. - private var typeGroupDependencies: [Int:Set] = [:] - private var selfReferences: [Variable: [(inout JSTyper, Variable?) -> ()]] = [:] + private var typeGroupDependencies: [Int: Set] = [:] + private var selfReferences: [Variable: [(inout JSTyper, Variable?) -> Void]] = [:] private var isWithinTypeGroup = false // Tracks the type definition variable for each Wasm index type. - private var wasmTypeDefMap = [WasmTypeDescription:Variable]() + private var wasmTypeDefMap = [WasmTypeDescription: Variable]() // Tracks the active function definitions and contains the instruction that started the function. private var activeFunctionDefinitions = Stack() @@ -64,7 +64,7 @@ public struct JSTyper: Analyzer { var functionImports: [(Variable, Signature)] = [] var functionDefines: [Variable] = [] - var globals : [Variable] { + var globals: [Variable] { return globalImports + globalDefines } @@ -124,12 +124,16 @@ public struct JSTyper: Analyzer { var activeClasses = Stack() public func getGroup(withName name: String) -> ObjectGroup? { - if let group = activeObjectGroups.elementsStartingAtTop().first(where: {group in group.name == name}) { + if let group = activeObjectGroups.elementsStartingAtTop().first(where: { group in + group.name == name + }) { return group - } else if let cls = activeClasses.elementsStartingAtTop().first(where: {cls in cls.objectGroup.name == name}) { + } else if let cls = activeClasses.elementsStartingAtTop().first(where: { cls in + cls.objectGroup.name == name + }) { return cls.objectGroup } else { - return self.finalizedObjectGroups.first(where: {group in group.name == name}) + return self.finalizedObjectGroups.first(where: { group in group.name == name }) } } @@ -173,46 +177,66 @@ public struct JSTyper: Analyzer { public func createNewWasmModule() { let instanceName = "_fuzz_WasmModule\(numObjectGroups)" - let instanceType = ILType.object(ofGroup: instanceName, withProperties: ["exports"], withMethods: []) + let instanceType = ILType.object( + ofGroup: instanceName, withProperties: ["exports"], withMethods: []) let instanceNameExports = "_fuzz_WasmExports\(numObjectGroups)" - let instanceTypeExports = ILType.object(ofGroup: instanceNameExports, withProperties: [], withMethods: []) + let instanceTypeExports = ILType.object( + ofGroup: instanceNameExports, withProperties: [], withMethods: []) // This ObjectGroup tracking the Module itself is basically finished as it only has the `.exports` property // which we track, the rest is tracked on the ObjectGroup tracking the `.exports` field of this Module. // The ObjectGroup tracking the `.exports` field will be further modified to track exported functions and other properties. - let objectGroupModule = ObjectGroup(name: instanceName, instanceType: instanceType, properties: ["exports": instanceTypeExports], methods: [:]) + let objectGroupModule = ObjectGroup( + name: instanceName, instanceType: instanceType, + properties: ["exports": instanceTypeExports], methods: [:]) activeObjectGroups.push(objectGroupModule) - let objectGroupModuleExports = ObjectGroup(name: instanceNameExports, instanceType: instanceTypeExports, properties: [:], methods: [:]) + let objectGroupModuleExports = ObjectGroup( + name: instanceNameExports, instanceType: instanceTypeExports, properties: [:], + methods: [:]) activeObjectGroups.push(objectGroupModuleExports) } func createNewObjectLiteral() { let instanceName = "_fuzz_Object\(numObjectGroups)" - let instanceType: ILType = .object(ofGroup: instanceName, withProperties: [], withMethods: []) + let instanceType: ILType = .object( + ofGroup: instanceName, withProperties: [], withMethods: []) // This is the dynamic object group. - let objectGroup = ObjectGroup(name: instanceName, instanceType: instanceType, properties: [:], methods: [:]) + let objectGroup = ObjectGroup( + name: instanceName, instanceType: instanceType, properties: [:], methods: [:]) activeObjectGroups.push(objectGroup) } - func createNewClass(withSuperType superType: ILType, propertyMap: [String: ILType], methodMap: [String: [Signature]], superConstructorType: ILType, forOutput output: Variable) { + func createNewClass( + withSuperType superType: ILType, propertyMap: [String: ILType], + methodMap: [String: [Signature]], superConstructorType: ILType, + forOutput output: Variable + ) { let numGroups = numObjectGroups let instanceName = "_fuzz_Class\(numGroups)" // This type and the object group will be updated dynamically - let instanceType: ILType = .object(ofGroup: instanceName, withProperties: Array(superType.properties), withMethods: Array(superType.methods)) + let instanceType: ILType = .object( + ofGroup: instanceName, withProperties: Array(superType.properties), + withMethods: Array(superType.methods)) // This is the wip object group. - let objectGroup = ObjectGroup(name: instanceName, instanceType: instanceType, properties: propertyMap, overloads: methodMap) + let objectGroup = ObjectGroup( + name: instanceName, instanceType: instanceType, properties: propertyMap, + overloads: methodMap) activeObjectGroups.push(objectGroup) let classInstanceName = "_fuzz_Constructor\(numGroups)" - let classObjectGroup = ObjectGroup(name: classInstanceName, instanceType: .object(ofGroup: classInstanceName), properties: [:], overloads: [:]) + let classObjectGroup = ObjectGroup( + name: classInstanceName, instanceType: .object(ofGroup: classInstanceName), + properties: [:], overloads: [:]) - let classDefinition = ClassDefinition(output: output, objectGroup: classObjectGroup, superType: superType, superConstructorType: superConstructorType) + let classDefinition = ClassDefinition( + output: output, objectGroup: classObjectGroup, superType: superType, + superConstructorType: superConstructorType) activeClasses.push(classDefinition) } @@ -222,7 +246,8 @@ public struct JSTyper: Analyzer { public func addClassStaticProperty(propertyName: String) { let classType = activeClasses.top.objectGroup.instanceType - let newType = ILType.object(ofGroup: classType.group, withProperties: [propertyName]) + classType + let newType = + ILType.object(ofGroup: classType.group, withProperties: [propertyName]) + classType assert(newType != .nothing) activeClasses.top.objectGroup.properties[propertyName] = .jsAnything activeClasses.top.objectGroup.instanceType = newType @@ -230,17 +255,23 @@ public struct JSTyper: Analyzer { public func updateClassStaticPropertyType(propertyName: String, type: ILType) { assert(activeClasses.top.objectGroup.instanceType.properties.contains(propertyName)) - assert(activeClasses.top.objectGroup.properties.contains(where: {k, v in k == propertyName})) + assert( + activeClasses.top.objectGroup.properties.contains(where: { k, v in k == propertyName + })) activeClasses.top.objectGroup.properties[propertyName] = type } public func addClassStaticMethod(methodName: String) { let classType = activeClasses.top.objectGroup.instanceType - let newType = ILType.object(ofGroup: classType.group, withMethods: [methodName]) + classType + let newType = + ILType.object(ofGroup: classType.group, withMethods: [methodName]) + classType assert(newType != .nothing) activeClasses.top.objectGroup.instanceType = newType - activeClasses.top.objectGroup.methods[methodName] = activeClasses.top.objectGroup.methods[methodName] ?? [] + [Signature.forUnknownFunction] + activeClasses.top.objectGroup.methods[methodName] = + activeClasses.top.objectGroup.methods[methodName] ?? [] + [ + Signature.forUnknownFunction + ] activeClasses.top.objectGroup.instanceType = newType } @@ -269,12 +300,16 @@ public struct JSTyper: Analyzer { // as such "defined in Wasm" (i.e. requiredContext contains wasm) below means "defined in this module". // This is a feature as the module doesn't care as these imports always have to come from JS. - public func addWasmFunction(withSignature signature: Signature, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmFunction( + withSignature signature: Signature, forDefinition instr: Instruction, + forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. - let haveFunction = seenWasmVars.functionImports.contains(where: { - $0.0 == variable && $0.1 == signature - }) || seenWasmVars.functionDefines.contains(variable) + let haveFunction = + seenWasmVars.functionImports.contains(where: { + $0.0 == variable && $0.1 == signature + }) || seenWasmVars.functionDefines.contains(variable) if !haveFunction { if instr.op.requiredContext.inWasm { @@ -291,7 +326,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmGlobal(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmGlobal( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before if !seenWasmVars.globals.contains(variable) { @@ -308,7 +345,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmTable(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmTable( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -324,7 +363,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmMemory(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmMemory( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -340,7 +381,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmTag(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmTag( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -358,7 +401,9 @@ public struct JSTyper: Analyzer { public func addMethod(methodName: String, of groupType: ObjectGroupType) { let topGroup = activeObjectGroups.top - let newType = ILType.object(ofGroup: topGroup.name, withMethods: [methodName]) + topGroup.instanceType + let newType = + ILType.object(ofGroup: topGroup.name, withMethods: [methodName]) + + topGroup.instanceType assert(newType != .nothing) activeObjectGroups.top.instanceType = newType activeObjectGroups.top.methods[methodName] = [] @@ -376,7 +421,9 @@ public struct JSTyper: Analyzer { public func addProperty(propertyName: String) { let topGroup = activeObjectGroups.top - let newType = ILType.object(ofGroup: topGroup.name, withProperties: [propertyName]) + topGroup.instanceType + let newType = + ILType.object(ofGroup: topGroup.name, withProperties: [propertyName]) + + topGroup.instanceType assert(newType != .nothing) activeObjectGroups.top.instanceType = newType } @@ -413,7 +460,8 @@ public struct JSTyper: Analyzer { private mutating func registerWasmMemoryUse(for memory: Variable) { let definingInstruction = defUseAnalyzer.definition(of: memory) - dynamicObjectGroupManager.addWasmMemory(withType: type(of: memory), forDefinition: definingInstruction, forVariable: memory) + dynamicObjectGroupManager.addWasmMemory( + withType: type(of: memory), forDefinition: definingInstruction, forVariable: memory) } // Array for collecting type changes during instruction execution. @@ -452,7 +500,9 @@ public struct JSTyper: Analyzer { return typeDef } - mutating func addSignatureType(def: Variable, signature: WasmSignature, inputs: ArraySlice) { + mutating func addSignatureType( + def: Variable, signature: WasmSignature, inputs: ArraySlice + ) { assert(isWithinTypeGroup) var inputs = inputs.makeIterator() let tgIndex = typeGroups.count - 1 @@ -471,19 +521,25 @@ public struct JSTyper: Analyzer { if elementDesc == .selfReference { // Register a resolver callback. See `addArrayType` for details. if isParameter { - selfReferences[typeDef, default: []].append({typer, replacement in - let desc = typer.type(of: def).wasmTypeDefinition!.description as! WasmSignatureTypeDescription + selfReferences[typeDef, default: []].append({ typer, replacement in + let desc = + typer.type(of: def).wasmTypeDefinition!.description + as! WasmSignatureTypeDescription var params = desc.signature.parameterTypes let nullability = params[i].wasmReferenceType!.nullability - params[i] = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability) + params[i] = typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: nullability) desc.signature = params => desc.signature.outputTypes }) } else { - selfReferences[typeDef, default: []].append({typer, replacement in - let desc = typer.type(of: def).wasmTypeDefinition!.description as! WasmSignatureTypeDescription + selfReferences[typeDef, default: []].append({ typer, replacement in + let desc = + typer.type(of: def).wasmTypeDefinition!.description + as! WasmSignatureTypeDescription var outputTypes = desc.signature.outputTypes let nullability = outputTypes[i].wasmReferenceType!.nullability - outputTypes[i] = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability) + outputTypes[i] = typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: nullability) desc.signature = desc.signature.parameterTypes => outputTypes }) } @@ -495,24 +551,33 @@ public struct JSTyper: Analyzer { } let resolvedParameterTypes = signature.parameterTypes.enumerated().map(resolveType) - isParameter = false // TODO(mliedtke): Is there a nicer way to capture this? + isParameter = false // TODO(mliedtke): Is there a nicer way to capture this? let resolvedOutputTypes = signature.outputTypes.enumerated().map(resolveType) - set(def, .wasmTypeDef(description: WasmSignatureTypeDescription(signature: resolvedParameterTypes => resolvedOutputTypes, typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmSignatureTypeDescription( + signature: resolvedParameterTypes => resolvedOutputTypes, + typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } - mutating func addArrayType(def: Variable, elementType: ILType, mutability: Bool, elementRef: Variable? = nil) { + mutating func addArrayType( + def: Variable, elementType: ILType, mutability: Bool, elementRef: Variable? = nil + ) { assert(isWithinTypeGroup) let tgIndex = typeGroups.count - 1 let resolvedElementType: ILType if let elementRef = elementRef { let elementNullability = elementType.wasmReferenceType!.nullability let typeDefType = type(of: elementRef) - guard let elementDesc = typeDefType.wasmTypeDefinition?.description else { + guard let elementDesc = typeDefType.wasmTypeDefinition?.description else { // TODO(mliedtke): Investigate. The `typeDefType` should be `.wasmTypeDef`. // The `elementType` should be `.wasmRef(.Index)`? let missesDef = typeDefType.wasmTypeDefinition != nil - fatalError("Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), elementType = \(elementType)") + fatalError( + "Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), elementType = \(elementType)" + ) } if elementDesc == .selfReference { // Register a "resolver" callback that does one of the two: @@ -525,55 +590,71 @@ public struct JSTyper: Analyzer { // This callback will be called either when using a WasmResolveForwardReferenceType // operation (triggering case 2) or when reaching the wasmEndTypeGroup of the // current type group (case 1). - selfReferences[elementRef, default: []].append({typer, replacement in - (typer.type(of: def).wasmTypeDefinition!.description as! WasmArrayTypeDescription).elementType - = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) + selfReferences[elementRef, default: []].append({ typer, replacement in + (typer.type(of: def).wasmTypeDefinition!.description + as! WasmArrayTypeDescription).elementType = typer.type( + of: replacement ?? def + ).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) }) } - resolvedElementType = type(of: elementRef).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) + resolvedElementType = type(of: elementRef).wasmTypeDefinition!.getReferenceTypeTo( + nullability: elementNullability) registerTypeGroupDependency(from: tgIndex, to: elementDesc.typeGroupIndex) } else { resolvedElementType = elementType } - set(def, .wasmTypeDef(description: WasmArrayTypeDescription( - elementType: resolvedElementType, - mutability: mutability, - typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmArrayTypeDescription( + elementType: resolvedElementType, + mutability: mutability, + typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } - mutating func addStructType(def: Variable, fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)]) { + mutating func addStructType( + def: Variable, fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] + ) { let tgIndex = typeGroups.count - 1 let resolvedFields = fieldsWithRefs.enumerated().map { (fieldIndex, fieldWithInput) in let (field, fieldTypeRef) = fieldWithInput if let fieldTypeRef { let fieldNullability = field.type.wasmReferenceType!.nullability let typeDefType = type(of: fieldTypeRef) - guard let fieldTypeDesc = typeDefType.wasmTypeDefinition?.description else { + guard let fieldTypeDesc = typeDefType.wasmTypeDefinition?.description else { // TODO(mliedtke): Investigate. let missesDef = typeDefType.wasmTypeDefinition != nil - fatalError("Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), field.type = \(field.type)") + fatalError( + "Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), field.type = \(field.type)" + ) } if fieldTypeDesc == .selfReference { // Register a resolver callback. See `addArrayType` for details. - selfReferences[fieldTypeRef, default: []].append({typer, replacement in - (typer.type(of: def).wasmTypeDefinition!.description! as! WasmStructTypeDescription).fields[fieldIndex].type = - typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: fieldNullability) + selfReferences[fieldTypeRef, default: []].append({ typer, replacement in + (typer.type(of: def).wasmTypeDefinition!.description! + as! WasmStructTypeDescription).fields[fieldIndex].type = + typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: fieldNullability) }) } registerTypeGroupDependency(from: tgIndex, to: fieldTypeDesc.typeGroupIndex) return WasmStructTypeDescription.Field( - type: type(of: fieldTypeRef).wasmTypeDefinition!.getReferenceTypeTo(nullability: fieldNullability), + type: type(of: fieldTypeRef).wasmTypeDefinition!.getReferenceTypeTo( + nullability: fieldNullability), mutability: field.mutability) } else { return field } } - set(def, .wasmTypeDef(description: WasmStructTypeDescription( - fields: resolvedFields, typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmStructTypeDescription( + fields: resolvedFields, typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } @@ -608,7 +689,9 @@ public struct JSTyper: Analyzer { } mutating func setReferenceType(of: Variable, typeDef: Variable, nullability: Bool) { - setType(of: of, to: type(of: typeDef).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability)) + setType( + of: of, + to: type(of: typeDef).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability)) } // Returns the type description for the provided variable which has to be either a type @@ -624,7 +707,9 @@ public struct JSTyper: Analyzer { // Helper function to type a "regular" wasm begin block (block, if, try). mutating func wasmTypeBeginBlock(_ instr: Instruction, _ signature: WasmSignature) { setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(), signature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } } @@ -645,7 +730,7 @@ public struct JSTyper: Analyzer { // This typer is currently "Outside" of the wasm module, we just type // the instructions here such that we can set the type of the module at // the end. Figure out how we can set the correct type at the end? - if (instr.op is WasmOperation) { + if instr.op is WasmOperation { switch instr.op.opcode { case .consti64(_): setType(of: instr.output, to: .wasmi64) @@ -656,61 +741,61 @@ public struct JSTyper: Analyzer { case .constf32(_): setType(of: instr.output, to: .wasmf32) case .wasmi32CompareOp(_), - .wasmi64CompareOp(_), - .wasmf32CompareOp(_), - .wasmf64CompareOp(_): + .wasmi64CompareOp(_), + .wasmf32CompareOp(_), + .wasmf64CompareOp(_): setType(of: instr.output, to: .wasmi32) case .wasmi32EqualZero(_), - .wasmi64EqualZero(_): + .wasmi64EqualZero(_): setType(of: instr.output, to: .wasmi32) case .wasmi32BinOp(_), - .wasmi32UnOp(_), - .wasmWrapi64Toi32(_), - .wasmTruncatef32Toi32(_), - .wasmTruncatef64Toi32(_), - .wasmReinterpretf32Asi32(_), - .wasmSignExtend8Intoi32(_), - .wasmSignExtend16Intoi32(_), - .wasmTruncateSatf32Toi32(_), - .wasmTruncateSatf64Toi32(_): + .wasmi32UnOp(_), + .wasmWrapi64Toi32(_), + .wasmTruncatef32Toi32(_), + .wasmTruncatef64Toi32(_), + .wasmReinterpretf32Asi32(_), + .wasmSignExtend8Intoi32(_), + .wasmSignExtend16Intoi32(_), + .wasmTruncateSatf32Toi32(_), + .wasmTruncateSatf64Toi32(_): setType(of: instr.output, to: .wasmi32) case .wasmi64BinOp(_), - .wasmi64UnOp(_), - .wasmExtendi32Toi64(_), - .wasmTruncatef32Toi64(_), - .wasmTruncatef64Toi64(_), - .wasmReinterpretf64Asi64(_), - .wasmSignExtend8Intoi64(_), - .wasmSignExtend16Intoi64(_), - .wasmSignExtend32Intoi64(_), - .wasmTruncateSatf32Toi64(_), - .wasmTruncateSatf64Toi64(_): + .wasmi64UnOp(_), + .wasmExtendi32Toi64(_), + .wasmTruncatef32Toi64(_), + .wasmTruncatef64Toi64(_), + .wasmReinterpretf64Asi64(_), + .wasmSignExtend8Intoi64(_), + .wasmSignExtend16Intoi64(_), + .wasmSignExtend32Intoi64(_), + .wasmTruncateSatf32Toi64(_), + .wasmTruncateSatf64Toi64(_): setType(of: instr.output, to: .wasmi64) case .wasmf32BinOp(_), - .wasmf32UnOp(_), - .wasmConverti32Tof32(_), - .wasmConverti64Tof32(_), - .wasmDemotef64Tof32(_), - .wasmReinterpreti32Asf32(_): + .wasmf32UnOp(_), + .wasmConverti32Tof32(_), + .wasmConverti64Tof32(_), + .wasmDemotef64Tof32(_), + .wasmReinterpreti32Asf32(_): setType(of: instr.output, to: .wasmf32) case .wasmf64BinOp(_), - .wasmf64UnOp(_), - .wasmConverti32Tof64(_), - .wasmConverti64Tof64(_), - .wasmPromotef32Tof64(_), - .wasmReinterpreti64Asf64(_): + .wasmf64UnOp(_), + .wasmConverti32Tof64(_), + .wasmConverti64Tof64(_), + .wasmPromotef32Tof64(_), + .wasmReinterpreti64Asf64(_): setType(of: instr.output, to: .wasmf64) case .constSimd128(_), - .wasmSimd128Compare(_), - .wasmSimd128IntegerBinOp(_), - .wasmSimd128IntegerTernaryOp(_), - .wasmSimd128FloatUnOp(_), - .wasmSimd128FloatBinOp(_), - .wasmSimd128FloatTernaryOp(_), - .wasmSimdSplat(_), - .wasmSimdLoad(_), - .wasmSimdLoadLane(_), - .wasmSimdReplaceLane(_): + .wasmSimd128Compare(_), + .wasmSimd128IntegerBinOp(_), + .wasmSimd128IntegerTernaryOp(_), + .wasmSimd128FloatUnOp(_), + .wasmSimd128FloatBinOp(_), + .wasmSimd128FloatTernaryOp(_), + .wasmSimdSplat(_), + .wasmSimdLoad(_), + .wasmSimdLoadLane(_), + .wasmSimdReplaceLane(_): setType(of: instr.output, to: .wasmSimd128) case .wasmSimd128IntegerUnOp(let op): var outputType: ILType = .wasmSimd128 @@ -725,28 +810,44 @@ public struct JSTyper: Analyzer { case .wasmSimdExtractLane(let op): setType(of: instr.output, to: op.kind.laneType()) case .wasmDefineGlobal(let op): - let type = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: op.wasmGlobal.toType(), isMutable: op.isMutable)) - dynamicObjectGroupManager.addWasmGlobal(withType: type, forDefinition: instr, forVariable: instr.output) + let type = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType( + valueType: op.wasmGlobal.toType(), isMutable: op.isMutable)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type, forDefinition: instr, forVariable: instr.output) setType(of: instr.output, to: type) case .wasmDefineTable(let op): - setType(of: instr.output, to: .wasmTable(wasmTableType: WasmTableType(elementType: op.elementType, limits: op.limits, isTable64: op.isTable64, knownEntries: op.definedEntries))) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.output), forDefinition: instr, forVariable: instr.output) + setType( + of: instr.output, + to: .wasmTable( + wasmTableType: WasmTableType( + elementType: op.elementType, limits: op.limits, isTable64: op.isTable64, + knownEntries: op.definedEntries))) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.output), forDefinition: instr, + forVariable: instr.output) // Also re-export all functions that we now import through the activeElementSection for (idx, entry) in op.definedEntries.enumerated() { let definingInstruction = defUseAnalyzer.definition(of: instr.input(idx)) // TODO(cffsmith): Once we change the way we track signatures, we should also store the JS Signature here if we have one. The table might contain JS functions but we lose that signature in the entries. Which is why we convert back into JS Signatures here. - let jsSignature = ProgramBuilder.convertWasmSignatureToJsSignature(entry.signature) - dynamicObjectGroupManager.addWasmFunction(withSignature: jsSignature, forDefinition: definingInstruction, forVariable: instr.input(idx)) + let jsSignature = ProgramBuilder.convertWasmSignatureToJsSignature( + entry.signature) + dynamicObjectGroupManager.addWasmFunction( + withSignature: jsSignature, forDefinition: definingInstruction, + forVariable: instr.input(idx)) } case .wasmDefineElementSegment(let op): setType(of: instr.output, to: .wasmElementSegment(segmentLength: Int(op.size))) case .wasmDropElementSegment(_): type(of: instr.input(0)).wasmElementSegmentType!.markAsDropped() case .wasmTableInit(_), - .wasmTableCopy(_): + .wasmTableCopy(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - // Ignore changed function signatures - it is too hard to reason about them statically. + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) + // Ignore changed function signatures - it is too hard to reason about them statically. case .wasmDefineMemory(let op): setType(of: instr.output, to: op.wasmMemory) registerWasmMemoryUse(for: instr.output) @@ -756,31 +857,48 @@ public struct JSTyper: Analyzer { type(of: instr.input(0)).wasmDataSegmentType!.markAsDropped() case .wasmDefineTag(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.output, to: .object(ofGroup: "WasmTag", withWasmType: WasmTagType(signature.parameterTypes))) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.output), forDefinition: instr, forVariable: instr.output) + setType( + of: instr.output, + to: .object( + ofGroup: "WasmTag", withWasmType: WasmTagType(signature.parameterTypes))) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: instr.output), forDefinition: instr, + forVariable: instr.output) case .wasmThrow(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmLoadGlobal(let op): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: op.globalType) case .wasmStoreGlobal(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmTableGet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) let tableType = type(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: tableType, forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: tableType, forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: tableType.wasmTableType!.elementType) case .wasmTableSet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmTableSize(_), - .wasmTableGrow(_): + .wasmTableGrow(_): let isTable64 = type(of: instr.input(0)).wasmTableType?.isTable64 ?? false let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: isTable64 ? .wasmi64 : .wasmi32) case .wasmMemoryStore(_): registerWasmMemoryUse(for: instr.input(0)) @@ -799,7 +917,7 @@ public struct JSTyper: Analyzer { registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: op.op.type()) case .wasmMemorySize(_), - .wasmMemoryGrow(_): + .wasmMemoryGrow(_): let isMemory64 = type(of: instr.input(0)).wasmMemoryType?.isMemory64 ?? false registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: isMemory64 ? .wasmi64 : .wasmi32) @@ -812,14 +930,19 @@ public struct JSTyper: Analyzer { } let definingInstruction = defUseAnalyzer.definition(of: instr.input(1)) // Here we query the typer for the signature of the instruction as that is the correct "JS" Signature instead of taking the call-site specific converted wasm signature. - dynamicObjectGroupManager.addWasmFunction(withSignature: type(of: instr.input(1)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(1)) + dynamicObjectGroupManager.addWasmFunction( + withSignature: type(of: instr.input(1)).signature + ?? Signature.forUnknownFunction, forDefinition: definingInstruction, + forVariable: instr.input(1)) case .beginWasmFunction(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeBeginBlock(instr, signature) case .endWasmFunction(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature setType(of: instr.output, to: .wasmFunctionDef(signature)) - dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), forDefinition: instr, forVariable: instr.output) + dynamicObjectGroupManager.addWasmFunction( + withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), + forDefinition: instr, forVariable: instr.output) case .wasmSelect(_): setType(of: instr.output, to: type(of: instr.input(0))) case .wasmBeginBlock(_): @@ -837,7 +960,7 @@ public struct JSTyper: Analyzer { wasmTypeEndBlock(instr, signature.outputTypes) wasmTypeBeginBlock(instr, signature) case .wasmEndIf(_): - let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, signature.outputTypes) case .wasmBeginLoop(_): // Note that different to all other blocks the loop's label parameters are the input types @@ -845,7 +968,9 @@ public struct JSTyper: Analyzer { // beginning of the loop block instead of the end.) let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature setType(of: instr.innerOutputs.first!, to: .label(signature.parameterTypes)) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(), signature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } case .wasmEndLoop(_): @@ -857,14 +982,16 @@ public struct JSTyper: Analyzer { instr.inputs.forEach { input in if type(of: input).isWasmTagType { let definingInstruction = defUseAnalyzer.definition(of: input) - dynamicObjectGroupManager.addWasmTag(withType: type(of: input), forDefinition: definingInstruction, forVariable: input) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: input), forDefinition: definingInstruction, + forVariable: input) } } case .wasmEndTryTable(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, signature.outputTypes) case .wasmBeginTry(_): - let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeBeginBlock(instr, signature) case .wasmBeginCatchAll(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature @@ -877,7 +1004,8 @@ public struct JSTyper: Analyzer { // by this Wasm module. let tag = instr.input(1) let definingInstruction = defUseAnalyzer.definition(of: tag) - dynamicObjectGroupManager.addWasmTag(withType: type(of: tag), + dynamicObjectGroupManager.addWasmTag( + withType: type(of: tag), forDefinition: definingInstruction, forVariable: tag) // The second inner output is the exception label which is used for rethrowing the // exception with the legacy exception handling proposal. (This is similar to the @@ -887,7 +1015,9 @@ public struct JSTyper: Analyzer { // This guarantees that the inner outputs are properly typed, even if a mutator // changed the tag variable to something that's not typed as a Wasm tag anymore. let tagSignature = type(of: instr.input(2)).wasmFunctionSignatureDefSignature - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) + { setType(of: innerOutput, to: paramType) } for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) { @@ -907,15 +1037,15 @@ public struct JSTyper: Analyzer { for (output, outputType) in zip(instr.outputs, signature.outputTypes) { setType(of: output, to: outputType) } - // We don't need to update the DynamicObjectGroupManager, as all functions that can be called here are .wasmFunctionDef types, this means we have already added them when we saw the EndWasmFunction instruction. + // We don't need to update the DynamicObjectGroupManager, as all functions that can be called here are .wasmFunctionDef types, this means we have already added them when we saw the EndWasmFunction instruction. case .wasmCallIndirect(let op): for (output, outputType) in zip(instr.outputs, op.signature.outputTypes) { setType(of: output, to: outputType) } - // Functions that can be called through a table are also already added by the wasmDefineTable instruction. - // No need to analyze this and add them to the DynamicObjectGroupManager. + // Functions that can be called through a table are also already added by the wasmDefineTable instruction. + // No need to analyze this and add them to the DynamicObjectGroupManager. case .wasmArrayNewFixed(_), - .wasmArrayNewDefault(_): + .wasmArrayNewDefault(_): setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: false) case .wasmArrayLen(_): setType(of: instr.output, to: .wasmi32) @@ -925,13 +1055,13 @@ public struct JSTyper: Analyzer { case .wasmArraySet(_): break case .wasmStructNew(_), - .wasmStructNewDefault(_): + .wasmStructNewDefault(_): setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: false) case .wasmStructGet(let op): let typeDesc = getTypeDescription(of: instr.input(0)) as! WasmStructTypeDescription setType(of: instr.output, to: typeDesc.fields[op.fieldIndex].type.unpacked()) case .wasmStructSet(_): - break; + break case .wasmRefNull(let op): if instr.hasInputs { setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: true) @@ -951,7 +1081,8 @@ public struct JSTyper: Analyzer { case .wasmRefCast(let op): if op.type.requiredInputCount() == 1 { let nullable = op.type.wasmReferenceType!.nullability - setReferenceType(of: instr.output, typeDef: instr.input(1), nullability: nullable) + setReferenceType( + of: instr.output, typeDef: instr.input(1), nullability: nullable) } else { setType(of: instr.output, to: op.type) } @@ -964,7 +1095,8 @@ public struct JSTyper: Analyzer { // TODO(pawkra): forward shared bit & update the comment // extern.convert_any forwards the nullability from the input. let null = type(of: instr.input(0)).wasmReferenceType!.nullability - setType(of: instr.output, to: .wasmRef(.WasmExtern, shared: false, nullability: null)) + setType( + of: instr.output, to: .wasmRef(.WasmExtern, shared: false, nullability: null)) case .wasmDefineAdHocSignatureType(let op): startTypeGroup() addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) @@ -1036,7 +1168,9 @@ public struct JSTyper: Analyzer { } /// Sets a program-wide signature for the instruction at the given index, which must be the start of a function or method definition. - public mutating func setParameters(forSubroutineStartingAt index: Int, to parameterTypes: ParameterList) { + public mutating func setParameters( + forSubroutineStartingAt index: Int, to parameterTypes: ParameterList + ) { // Currently we expect this to only be used for the next instruction. assert(index == indexOfLastInstruction + 1) signatures[index] = parameterTypes @@ -1046,7 +1180,9 @@ public struct JSTyper: Analyzer { // Do lookup on our local type information first. if let groupName = objType.group { if let group = dynamicObjectGroupManager.getGroup(withName: groupName) { - if let signatures = group.methods[methodName], !signatures.isEmpty, objType.methods.contains(methodName) { + if let signatures = group.methods[methodName], !signatures.isEmpty, + objType.methods.contains(methodName) + { return signatures } else { // This means the objectGroup doesn't have the function but we did see the objectGroup. @@ -1069,9 +1205,13 @@ public struct JSTyper: Analyzer { if let groupName = objType.group { if let group = dynamicObjectGroupManager.getGroup(withName: groupName) { // Check if we have it in the group and on the actual passed in ILType as it might've been deleted. - if let type = group.properties[propertyName], objType.properties.contains(propertyName) { + if let type = group.properties[propertyName], + objType.properties.contains(propertyName) + { return type - } else if let type = group.methods[propertyName], objType.methods.contains(propertyName) { + } else if let type = group.methods[propertyName], + objType.methods.contains(propertyName) + { // If no property is present, look up the name in the methods instead. // Retrieving a method "as a property" results in a variable that is a function // with the method's signature. However, it loses the this-binding: @@ -1104,7 +1244,9 @@ public struct JSTyper: Analyzer { /// Attempts to infer the constructed type of the given constructor. public func inferConstructedType(of constructor: Variable) -> ILType { - if let signature = state.type(of: constructor).constructorSignature, signature.outputType != .jsAnything { + if let signature = state.type(of: constructor).constructorSignature, + signature.outputType != .jsAnything + { return signature.outputType } return .object() @@ -1129,8 +1271,12 @@ public struct JSTyper: Analyzer { /// Attempts to infer the parameter types of the given subroutine definition. /// If parameter types have been added for this function, they are returned, otherwise generic parameter types (i.e. .jsAnything parameters) for the parameters specified in the operation are generated. - private func inferSubroutineParameterList(of op: BeginAnySubroutine, at index: Int) -> ParameterList { - return signatures[index] ?? ParameterList(numParameters: op.parameters.count, hasRestParam: op.parameters.hasRestParameter) + private func inferSubroutineParameterList(of op: BeginAnySubroutine, at index: Int) + -> ParameterList + { + return signatures[index] + ?? ParameterList( + numParameters: op.parameters.count, hasRestParam: op.parameters.hasRestParameter) } // Set type to current state and save type change event @@ -1156,15 +1302,22 @@ public struct JSTyper: Analyzer { case .beginPlainFunction(let op): // Plain functions can also be used as constructors. // The return value type will only be known after fully processing the function definitions. - set(instr.output, .functionAndConstructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + set( + instr.output, + .functionAndConstructor( + inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): - set(instr.output, .function(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + set( + instr.output, + .function(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginConstructor(let op): - set(instr.output, .constructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + set( + instr.output, + .constructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginCodeString: set(instr.output, .jsString) case .beginClassDefinition(let op): @@ -1177,18 +1330,25 @@ public struct JSTyper: Analyzer { // the |this| value inside the constructor. However, we don't currently support multiple signatures // for the same callable (the call signature and the construct signature), so here in that case // we just ignore the super type. - if let constructorReturnType = superConstructorType.constructorSignature?.outputType, constructorReturnType.Is(.object()) { + if let constructorReturnType = superConstructorType.constructorSignature? + .outputType, constructorReturnType.Is(.object()) + { superType = constructorReturnType } } - let propertySuperTypeMap = Dictionary(uniqueKeysWithValues: superType.properties.map { name in - (name, inferPropertyType(of: name, on: superType)) - }) - let methodSuperTypeMap = Dictionary(uniqueKeysWithValues: superType.methods.map { name in - (name, inferMethodSignatures(of: name, on: superType)) - }) + let propertySuperTypeMap = Dictionary( + uniqueKeysWithValues: superType.properties.map { name in + (name, inferPropertyType(of: name, on: superType)) + }) + let methodSuperTypeMap = Dictionary( + uniqueKeysWithValues: superType.methods.map { name in + (name, inferMethodSignatures(of: name, on: superType)) + }) - dynamicObjectGroupManager.createNewClass(withSuperType: superType, propertyMap: propertySuperTypeMap, methodMap: methodSuperTypeMap, superConstructorType: superConstructorType, forOutput: instr.output) + dynamicObjectGroupManager.createNewClass( + withSuperType: superType, propertyMap: propertySuperTypeMap, + methodMap: methodSuperTypeMap, superConstructorType: superConstructorType, + forOutput: instr.output) // We only know here that this is going to be a constructor() type. // On endClassDefinition below, the exact type is refined. But we @@ -1197,7 +1357,10 @@ public struct JSTyper: Analyzer { set(instr.output, .constructor()) case .endClassDefinition: let (instanceType, classDefinition) = dynamicObjectGroupManager.finalizeClass() - set(classDefinition.output, classDefinition.objectGroup.instanceType + .constructor(classDefinition.constructorParameters => instanceType)) + set( + classDefinition.output, + classDefinition.objectGroup.instanceType + + .constructor(classDefinition.constructorParameters => instanceType)) default: // Only instructions starting a block with output variables should be handled here. assert(instr.numOutputs == 0 || !instr.isBlockStart) @@ -1210,13 +1373,13 @@ public struct JSTyper: Analyzer { } switch instr.op.opcode { case .beginObjectLiteral, - .endObjectLiteral, - .beginClassDefinition, - .endClassDefinition, - .beginClassStaticInitializer, - .endClassStaticInitializer, - .beginWasmModule, - .endWasmModule: + .endObjectLiteral, + .beginClassDefinition, + .endClassDefinition, + .beginClassStaticInitializer, + .endClassStaticInitializer, + .beginWasmModule, + .endWasmModule: // Object literals and class definitions don't create any conditional branches, only methods and accessors inside of them. These are handled further below. break case .beginIf: @@ -1244,12 +1407,12 @@ public struct JSTyper: Analyzer { // Loop headers execute unconditionally (at least once). break case .beginDoWhileLoopBody, - .beginDoWhileLoopHeader, - .endDoWhileLoop: + .beginDoWhileLoopHeader, + .endDoWhileLoop: // Do-While loop headers _and_ bodies execute unconditionally (at least once). break case .beginForLoopInitializer, - .beginForLoopCondition: + .beginForLoopCondition: // The initializer and the condition of a for-loop's header execute unconditionally. break case .beginForLoopAfterthought: @@ -1266,66 +1429,66 @@ public struct JSTyper: Analyzer { case .endForLoop: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginWhileLoopBody, - .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct, - .beginRepeatLoop, - .beginCodeString: + .beginForInLoop, + .beginForOfLoop, + .beginForOfLoopWithDestruct, + .beginRepeatLoop, + .beginCodeString: state.startGroupOfConditionallyExecutingBlocks() // Push an empty state representing the case when the loop body (or code string) is not executed at all state.enterConditionallyExecutingBlock(typeChanges: &typeChanges) // Push a new state tracking the types inside the loop state.enterConditionallyExecutingBlock(typeChanges: &typeChanges) case .endWhileLoop, - .endForInLoop, - .endForOfLoop, - .endRepeatLoop, - .endCodeString: + .endForInLoop, + .endForOfLoop, + .endRepeatLoop, + .endCodeString: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter, - .beginPlainFunction, - .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor, - .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassPrivateMethod: + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, + .beginPlainFunction, + .beginArrowFunction, + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor, + .beginClassConstructor, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter, - .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endConstructor, - .endClassConstructor, - .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter, - .endClassPrivateMethod: + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, + .endPlainFunction, + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endConstructor, + .endClassConstructor, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter, + .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). // @@ -1337,7 +1500,8 @@ public struct JSTyper: Analyzer { defaultReturnValueType = type(of: begin.innerOutput(0)) } - let returnValueType = state.endSubroutine(typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) + let returnValueType = state.endSubroutine( + typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) // Check if the signature is needed, otherwise, we don't need the return value type. if begin.numOutputs == 1 { @@ -1346,13 +1510,20 @@ public struct JSTyper: Analyzer { if let signature = funcType.signature { switch begin.op.opcode { case .beginGeneratorFunction, - .beginAsyncGeneratorFunction: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => .jsGenerator)) + .beginAsyncGeneratorFunction: + setType( + of: begin.output, + to: funcType.settingSignature(to: signature.parameters => .jsGenerator)) case .beginAsyncFunction, - .beginAsyncArrowFunction: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => .jsPromise)) + .beginAsyncArrowFunction: + setType( + of: begin.output, + to: funcType.settingSignature(to: signature.parameters => .jsPromise)) default: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => returnValueType)) + setType( + of: begin.output, + to: funcType.settingSignature( + to: signature.parameters => returnValueType)) } } } @@ -1364,57 +1535,71 @@ public struct JSTyper: Analyzer { assert(begin.op is BeginClassMethod) let beginOp = begin.op as! BeginClassMethod if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateClassStaticMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) } else { - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) } case .endClassGetter(_): assert(begin.op is BeginClassGetter) let beginOp = begin.op as! BeginClassGetter if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } else { - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } case .endClassSetter(_): assert(begin.op is BeginClassSetter) let beginOp = begin.op as! BeginClassSetter if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } else { - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } case .endObjectLiteralMethod(_): assert(begin.op is BeginObjectLiteralMethod) let beginOp = begin.op as! BeginObjectLiteralMethod - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) case .endObjectLiteralGetter(_): assert(begin.op is BeginObjectLiteralGetter) let beginOp = begin.op as! BeginObjectLiteralGetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) case .endObjectLiteralSetter(_): assert(begin.op is BeginObjectLiteralSetter) let beginOp = begin.op as! BeginObjectLiteralSetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) default: break } - case .beginTry, - .beginCatch, - .beginFinally, - .endTryCatchFinally: + .beginCatch, + .beginFinally, + .endTryCatchFinally: break case .beginWith, - .endWith: + .endWith: break case .beginBlockStatement, - .endBlockStatement: + .endBlockStatement: break case .wasmBeginTypeGroup, - .wasmEndTypeGroup: - break + .wasmEndTypeGroup: + break default: assert(instr.isSimple) } @@ -1425,7 +1610,9 @@ public struct JSTyper: Analyzer { return } // Helper function to process parameters - func processParameterDeclarations(_ parameterVariables: ArraySlice, parameters: ParameterList) { + func processParameterDeclarations( + _ parameterVariables: ArraySlice, parameters: ParameterList + ) { let types = computeParameterTypes(from: parameters) assert(types.count == parameterVariables.count) for (param, type) in zip(parameterVariables, types) { @@ -1445,26 +1632,28 @@ public struct JSTyper: Analyzer { // TODO: fetch all output types from the environment instead of hardcoding them. // Helper function to set output type of binary/reassignment operations - func analyzeBinaryOperation(operator op: BinaryOperator, withInputs inputs: ArraySlice) -> ILType { + func analyzeBinaryOperation( + operator op: BinaryOperator, withInputs inputs: ArraySlice + ) -> ILType { switch op { case .Add: return maybeBigIntOr(.primitive) case .Sub, - .Mul, - .Exp, - .Div, - .Mod: + .Mul, + .Exp, + .Div, + .Mod: return maybeBigIntOr(.number) case .BitAnd, - .BitOr, - .Xor, - .LShift, - .RShift, - .UnRShift: + .BitOr, + .Xor, + .LShift, + .RShift, + .UnRShift: return maybeBigIntOr(.integer) case .LogicAnd, - .LogicOr, - .NullCoalesce: + .LogicOr, + .NullCoalesce: return state.type(of: inputs[0]) | state.type(of: inputs[1]) } } @@ -1526,7 +1715,7 @@ public struct JSTyper: Analyzer { case .createNamedVariable(let op): if op.hasInitialValue { set(instr.output, type(ofInput: 0)) - } else if (environment.hasBuiltin(op.variableName)) { + } else if environment.hasBuiltin(op.variableName) { set(instr.output, environment.type(ofBuiltin: op.variableName)) } else { set(instr.output, .jsAnything) @@ -1554,24 +1743,29 @@ public struct JSTyper: Analyzer { dynamicObjectGroupManager.createNewObjectLiteral() case .objectLiteralAddProperty(let op): - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName, withType: type(ofInput: 0)) + dynamicObjectGroupManager.addProperty( + propertyName: op.propertyName, withType: type(ofInput: 0)) case .objectLiteralAddElement, - .objectLiteralAddComputedProperty, - .objectLiteralCopyProperties: + .objectLiteralAddComputedProperty, + .objectLiteralCopyProperties: // We cannot currently determine the properties/methods added by these operations. break case .beginObjectLiteralMethod(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .objectLiteral) case .beginObjectLiteralComputedMethod(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginObjectLiteralGetter(let op): // The first inner output is the explicit |this| parameter for the constructor @@ -1587,13 +1781,17 @@ public struct JSTyper: Analyzer { // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) case .beginObjectLiteralComputedSetter(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .endObjectLiteral: let instanceType = dynamicObjectGroupManager.finalizeObjectLiteral() @@ -1609,41 +1807,57 @@ public struct JSTyper: Analyzer { case .classAddProperty(let op): if op.isStatic { dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: op.propertyName, + type: op.hasValue ? type(ofInput: 0) : .jsAnything) } else { dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + dynamicObjectGroupManager.updatePropertyType( + propertyName: op.propertyName, + type: op.hasValue ? type(ofInput: 0) : .jsAnything) } case .beginClassStaticInitializer: // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) case .beginClassMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassComputedMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassGetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) } else { @@ -1654,7 +1868,9 @@ public struct JSTyper: Analyzer { case .beginClassComputedGetter(let op): if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } @@ -1662,36 +1878,48 @@ public struct JSTyper: Analyzer { case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) } assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassComputedSetter(let op): if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .createArray, - .createIntArray, - .createFloatArray, - .createArrayWithSpread: + .createIntArray, + .createFloatArray, + .createArrayWithSpread: set(instr.output, .jsArray) case .createTemplateString: @@ -1713,18 +1941,18 @@ public struct JSTyper: Analyzer { set(instr.input(0), type(ofInput: 0).removing(propertyOrMethod: op.propertyName)) set(instr.output, .boolean) - // TODO: An additional analyzer is required to determine the runtime value of the input variable + // TODO: An additional analyzer is required to determine the runtime value of the input variable case .deleteComputedProperty, - .deleteElement: + .deleteElement: set(instr.output, .boolean) - // TODO: An additional analyzer is required to determine the runtime value of the output variable generated from the following operations - // For now we treat this as .jsAnything + // TODO: An additional analyzer is required to determine the runtime value of the output variable generated from the following operations + // For now we treat this as .jsAnything case .getElement, - .getComputedProperty, - .getComputedSuperProperty, - .callComputedMethod, - .callComputedMethodWithSpread: + .getComputedProperty, + .getComputedSuperProperty, + .callComputedMethod, + .callComputedMethodWithSpread: set(instr.output, .jsAnything) case .ternaryOperation: @@ -1732,11 +1960,11 @@ public struct JSTyper: Analyzer { set(instr.output, outputType) case .callFunction, - .callFunctionWithSpread: + .callFunctionWithSpread: set(instr.output, inferCallResultType(of: instr.input(0))) case .construct, - .constructWithSpread: + .constructWithSpread: set(instr.output, inferConstructedType(of: instr.input(0))) case .callMethod(let op): @@ -1744,18 +1972,21 @@ public struct JSTyper: Analyzer { // op.numInputs - 1 because the signature.numParameters does not include the receiver. // TODO: We could make the overload resolution here more accurate // by also comparing the types of parameters. - let sig = sigs.filter({$0.numParameters == op.numInputs - 1}).first ?? chooseUniform(from: sigs) + let sig = + sigs.filter({ $0.numParameters == op.numInputs - 1 }).first + ?? chooseUniform(from: sigs) set(instr.output, sig.outputType) case .callMethodWithSpread(let op): - let sig = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) + let sig = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) set(instr.output, sig.outputType) case .unaryOperation(let op): switch op.op { case .PreInc, - .PreDec, - .PostInc, - .PostDec: + .PreDec, + .PostInc, + .PostDec: set(instr.input(0), maybeBigIntOr(.primitive)) set(instr.output, maybeBigIntOr(.primitive)) case .Plus: @@ -1803,10 +2034,10 @@ public struct JSTyper: Analyzer { } case .destructArray: - instr.outputs.forEach{set($0, .jsAnything)} + instr.outputs.forEach { set($0, .jsAnything) } case .destructArrayAndReassign: - instr.inputs.dropFirst().forEach{set($0, .jsAnything)} + instr.inputs.dropFirst().forEach { set($0, .jsAnything) } case .destructObject(let op): for (property, output) in zip(op.properties, instr.outputs) { @@ -1848,20 +2079,25 @@ public struct JSTyper: Analyzer { } case .beginPlainFunction(let op as BeginAnyFunction), - .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): - processParameterDeclarations(instr.innerOutputs, parameters: inferSubroutineParameterList(of: op, at: instr.index)) + .beginArrowFunction(let op as BeginAnyFunction), + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + processParameterDeclarations( + instr.innerOutputs, + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginConstructor(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), .object()) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .callSuperMethod(let op): - let sig = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: currentSuperType())) + let sig = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: currentSuperType())) set(instr.output, sig.outputType) case .getPrivateProperty: @@ -1875,7 +2111,7 @@ public struct JSTyper: Analyzer { case .getSuperProperty(let op): set(instr.output, inferPropertyType(of: op.propertyName, on: currentSuperType())) - // TODO: support superclass property assignment + // TODO: support superclass property assignment case .beginForLoopCondition: // For now, we use only the initial type of the loop variables (at the point of the for-loop's initializer block) @@ -1916,26 +2152,46 @@ public struct JSTyper: Analyzer { // TODO: also add other macro instructions here. case .createWasmGlobal(let op): - set(instr.output, .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: op.value.toType(), isMutable: op.isMutable))) + set( + instr.output, + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType( + valueType: op.value.toType(), isMutable: op.isMutable))) case .createWasmMemory(let op): - set(instr.output, .wasmMemory(limits: op.memType.limits, isShared: op.memType.isShared, isMemory64: op.memType.isMemory64)) + set( + instr.output, + .wasmMemory( + limits: op.memType.limits, isShared: op.memType.isShared, + isMemory64: op.memType.isMemory64)) case .createWasmTable(let op): - set(instr.output, .wasmTable(wasmTableType: WasmTableType(elementType: op.tableType.elementType, limits: op.tableType.limits, isTable64: op.tableType.isTable64, knownEntries: []))) + set( + instr.output, + .wasmTable( + wasmTableType: WasmTableType( + elementType: op.tableType.elementType, limits: op.tableType.limits, + isTable64: op.tableType.isTable64, knownEntries: []))) case .createWasmJSTag(_): - set(instr.output, .object(ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true))) + set( + instr.output, + .object( + ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true) + )) case .createWasmTag(let op): - set(instr.output, .object(ofGroup: "WasmTag", withWasmType: WasmTagType(op.parameterTypes))) + set( + instr.output, + .object(ofGroup: "WasmTag", withWasmType: WasmTagType(op.parameterTypes))) case .wrapSuspending(_): // This operation takes a function but produces an object that can be called from WebAssembly. // TODO: right now this "loses" the signature of the JS function, this is unfortunate but won't break fuzzing, in the template we can just store the signature. // The WasmJsCall generator just won't work as it requires a callable. // In the future we should also attach a WasmTypeExtension to this object that stores the signature of input(0) here. - set(instr.output, .object(ofGroup:"WasmSuspendingObject")) + set(instr.output, .object(ofGroup: "WasmSuspendingObject")) case .wrapPromising(_): // Here we basically pass through the type transparently as we just annotate this exported function as "promising" @@ -1943,7 +2199,8 @@ public struct JSTyper: Analyzer { set(instr.output, type(ofInput: 0)) case .bindMethod(let op): - let signature = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) + let signature = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) // We need to prepend the this argument now. We pick .object() here as the widest type because of the following: // - a lot of builtin methods (such as the ones on `Array.prototype`) work on any JavaScript object // - [$constructor.prototype.foo.bind] is a common pattern and the `this` would be set to the type of constructor.prototype instead of the constructor's instance type. @@ -1973,7 +2230,7 @@ public struct JSTyper: Analyzer { case .wasmEndTypeGroup(_): // For now just forward the type information based on the inputs. - zip(instr.inputs, instr.outputs).forEach {input, output in + zip(instr.inputs, instr.outputs).forEach { input, output in set(output, state.type(of: input)) } finishTypeGroup() @@ -1986,11 +2243,14 @@ public struct JSTyper: Analyzer { case .wasmDefineArrayType(let op): let elementRef = op.elementType.requiredInputCount() == 1 ? instr.input(0) : nil - addArrayType(def: instr.output, elementType: op.elementType, mutability: op.mutability, elementRef: elementRef) + addArrayType( + def: instr.output, elementType: op.elementType, mutability: op.mutability, + elementRef: elementRef) case .wasmDefineStructType(let op): var inputIndex = 0 - let fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] = op.fields.map { field in + let fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] = op.fields.map { + field in if field.type.requiredInputCount() == 0 { return (field, nil) } else { @@ -2019,7 +2279,9 @@ public struct JSTyper: Analyzer { default: // Only simple instructions and block instruction with inner outputs are handled here - assert(instr.isNop || (instr.numOutputs == 0 || (instr.isBlock && instr.numInnerOutputs == 0))) + assert( + instr.isNop + || (instr.numOutputs == 0 || (instr.isBlock && instr.numInnerOutputs == 0))) } // We explicitly type the outputs of guarded operations as .jsAnything for two reasons: @@ -2146,7 +2408,11 @@ public struct JSTyper: Analyzer { assert(parentState === states.secondToTop.last!) // If an oldType is specified, it must match the type in the next most recent state // (but here we just check that one of the parent states contains it). - assert(oldType == nil || states.elementsStartingAtTop().contains(where: { $0.last!.types[v] == oldType! })) + assert( + oldType == nil + || states.elementsStartingAtTop().contains(where: { + $0.last!.types[v] == oldType! + })) // Set the old type in the parent state if it doesn't yet exist to satisfy "activeState[v] != nil => parentState[v] != nil". // Use .nothing to express that the variable is only defined in the child state. @@ -2164,7 +2430,10 @@ public struct JSTyper: Analyzer { } mutating func updateReturnValueType(to t: ILType) { - assert(states.elementsStartingAtTop().contains(where: { $0.last!.isSubroutineState }), "Handling a `return` but neither the active state nor any of its parent states represents a subroutine") + assert( + states.elementsStartingAtTop().contains(where: { $0.last!.isSubroutineState }), + "Handling a `return` but neither the active state nor any of its parent states represents a subroutine" + ) guard !activeState.hasReturned else { // In this case, we have already set the return value in this branch of (conditional) // execution and so are executing inside dead code, so don't update the return value. @@ -2189,7 +2458,9 @@ public struct JSTyper: Analyzer { /// Enter a new conditionally executing block and append it to the currently active group of such blocks. /// As such, either this block or one of its "sibling" blocks in the current group may execute at runtime. - mutating func enterConditionallyExecutingBlock(typeChanges: inout [(Variable, ILType)], isDefaultSwitchCaseState: Bool = false) { + mutating func enterConditionallyExecutingBlock( + typeChanges: inout [(Variable, ILType)], isDefaultSwitchCaseState: Bool = false + ) { assert(states.top.isEmpty || !states.top.last!.isSubroutineState) // Reset current state to parent state @@ -2198,7 +2469,9 @@ public struct JSTyper: Analyzer { // 1. Variable does not exist in sibling scope (t == .nothing) // 2. Variable is only local in sibling state (parent == .nothing) // 3. No type change happened - if t != .nothing && parentState.types[v] != .nothing && parentState.types[v] != overallState.types[v] { + if t != .nothing && parentState.types[v] != .nothing + && parentState.types[v] != overallState.types[v] + { typeChanges.append((v, parentState.types[v]!)) overallState.types[v] = parentState.types[v]! } @@ -2212,8 +2485,11 @@ public struct JSTyper: Analyzer { /// /// This will compute the new variable types assuming that exactly one of the blocks in the group will be executed /// at runtime and will then return to the previously active state. - mutating func endGroupOfConditionallyExecutingBlocks(typeChanges: inout [(Variable, ILType)]) { - let returnValueType = mergeNewestConditionalBlocks(typeChanges: &typeChanges, defaultReturnValueType: .nothing) + mutating func endGroupOfConditionallyExecutingBlocks( + typeChanges: inout [(Variable, ILType)] + ) { + let returnValueType = mergeNewestConditionalBlocks( + typeChanges: &typeChanges, defaultReturnValueType: .nothing) assert(returnValueType == nil) } @@ -2233,7 +2509,8 @@ public struct JSTyper: Analyzer { /// Enter a new conditionally executing block representing a default switch case. mutating func enterSwitchDefaultCase(typeChanges: inout [(Variable, ILType)]) { - enterConditionallyExecutingBlock(typeChanges: &typeChanges, isDefaultSwitchCaseState: true) + enterConditionallyExecutingBlock( + typeChanges: &typeChanges, isDefaultSwitchCaseState: true) } /// Finalizes the current group of conditionally executing blocks representing a switch construct. @@ -2276,8 +2553,13 @@ public struct JSTyper: Analyzer { /// /// This behaves similar to `endGroupOfConditionallyExecutingBlocks()` and computes variable type changes assuming that the\ /// function body may or may not have been executed, but it additionally computes and returns the inferred type for the subroutine's return value. - mutating func endSubroutine(typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType) -> ILType { - guard let returnValueType = mergeNewestConditionalBlocks(typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) else { + mutating func endSubroutine( + typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType + ) -> ILType { + guard + let returnValueType = mergeNewestConditionalBlocks( + typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) + else { fatalError("Leaving a subroutine that was never entered") } return returnValueType @@ -2287,17 +2569,22 @@ public struct JSTyper: Analyzer { /// /// This computes the new types assuming that exactly one of the conditional blocks will execute at runtime. If the currently /// active state is a subroutine state, this will return the final return value type, otherwise it will return nil. - private mutating func mergeNewestConditionalBlocks(typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType) -> ILType? { + private mutating func mergeNewestConditionalBlocks( + typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType + ) -> ILType? { let statesToMerge = states.pop() - let maybeReturnValueType = computeReturnValueType(whenMerging: statesToMerge, defaultReturnValueType: defaultReturnValueType) + let maybeReturnValueType = computeReturnValueType( + whenMerging: statesToMerge, defaultReturnValueType: defaultReturnValueType) let newTypes = computeVariableTypes(whenMerging: statesToMerge) makeParentStateTheActiveStateAndUpdateVariableTypes(to: newTypes, &typeChanges) return maybeReturnValueType } - private func computeReturnValueType(whenMerging states: [State], defaultReturnValueType: ILType) -> ILType? { + private func computeReturnValueType( + whenMerging states: [State], defaultReturnValueType: ILType + ) -> ILType? { assert(states.last === activeState) // Need to compute how many sibling states have returned and what their overall return value type is. @@ -2375,7 +2662,9 @@ public struct JSTyper: Analyzer { return newTypes } - private mutating func makeParentStateTheActiveStateAndUpdateVariableTypes(to newTypes: VariableMap, _ typeChanges: inout [(Variable, ILType)]) { + private mutating func makeParentStateTheActiveStateAndUpdateVariableTypes( + to newTypes: VariableMap, _ typeChanges: inout [(Variable, ILType)] + ) { // The previous parent state is now the active state let oldParentState = parentState activeState = parentState diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 2770d45f1..958602acf 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -14,8 +14,15 @@ /// A JavaScript operation in the FuzzIL language. class JsOperation: Operation { - override init(numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .javascript, contextOpened: Context = .empty) { - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, firstVariadicInput: firstVariadicInput, attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + override init( + numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .javascript, contextOpened: Context = .empty + ) { + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + firstVariadicInput: firstVariadicInput, attributes: attributes, + requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -50,10 +57,19 @@ class GuardableOperation: JsOperation { /// is emitted around the operation or not. let isGuarded: Bool - init(isGuarded: Bool, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .javascript) { - assert(attributes.isDisjoint(with: [.isBlockStart, .isBlockEnd]), "Only simple operations can be guardable") + init( + isGuarded: Bool, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .javascript + ) { + assert( + attributes.isDisjoint(with: [.isBlockStart, .isBlockEnd]), + "Only simple operations can be guardable") self.isGuarded = isGuarded - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, firstVariadicInput: firstVariadicInput, attributes: attributes, requiredContext: requiredContext) + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + firstVariadicInput: firstVariadicInput, attributes: attributes, + requiredContext: requiredContext) } // Helper functions to enable guards. @@ -82,19 +98,25 @@ class GuardableOperation: JsOperation { case .callFunction(let op): return CallFunction(numArguments: op.numArguments, isGuarded: true) case .callFunctionWithSpread(let op): - return CallFunctionWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallFunctionWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) case .construct(let op): return Construct(numArguments: op.numArguments, isGuarded: true) case .constructWithSpread(let op): - return ConstructWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return ConstructWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) case .callMethod(let op): - return CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: true) + return CallMethod( + methodName: op.methodName, numArguments: op.numArguments, isGuarded: true) case .callMethodWithSpread(let op): - return CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, + isGuarded: true) case .callComputedMethod(let op): return CallComputedMethod(numArguments: op.numArguments, isGuarded: true) case .callComputedMethodWithSpread(let op): - return CallComputedMethodWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallComputedMethodWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) default: fatalError("All guardable operations should be handled") } @@ -126,19 +148,25 @@ class GuardableOperation: JsOperation { case .callFunction(let op): return CallFunction(numArguments: op.numArguments, isGuarded: false) case .callFunctionWithSpread(let op): - return CallFunctionWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallFunctionWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) case .construct(let op): return Construct(numArguments: op.numArguments, isGuarded: false) case .constructWithSpread(let op): - return ConstructWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return ConstructWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) case .callMethod(let op): - return CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: false) + return CallMethod( + methodName: op.methodName, numArguments: op.numArguments, isGuarded: false) case .callMethodWithSpread(let op): - return CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, + isGuarded: false) case .callComputedMethod(let op): return CallComputedMethod(numArguments: op.numArguments, isGuarded: false) case .callComputedMethodWithSpread(let op): - return CallComputedMethodWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallComputedMethodWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) default: fatalError("All guardable operations should be handled") } @@ -272,7 +300,7 @@ final class LoadArguments: JsOperation { /// baz += "bla"; /// print(baz); /// -public enum NamedVariableDeclarationMode : CaseIterable { +public enum NamedVariableDeclarationMode: CaseIterable { // The variable is assumed to already exist and therefore is not declared again. // This is for example used for global variables and builtins, but also to support // variable and function hoisting where an identifier is used before it is defined. @@ -304,7 +332,8 @@ final class CreateNamedVariable: JsOperation { init(_ name: String, declarationMode: NamedVariableDeclarationMode) { self.variableName = name self.declarationMode = declarationMode - super.init(numInputs: declarationMode == .none ? 0 : 1, numOutputs: 1, attributes: .isMutable) + super.init( + numInputs: declarationMode == .none ? 0 : 1, numOutputs: 1, attributes: .isMutable) } } @@ -405,42 +434,44 @@ public struct RegExpFlags: OptionSet, Hashable { return flags } - static let empty = RegExpFlags([]) - static let caseInsensitive = RegExpFlags(rawValue: 1 << 0) // i - static let global = RegExpFlags(rawValue: 1 << 1) // g - static let multiline = RegExpFlags(rawValue: 1 << 2) // m - static let dotall = RegExpFlags(rawValue: 1 << 3) // s - static let unicode = RegExpFlags(rawValue: 1 << 4) // u - static let sticky = RegExpFlags(rawValue: 1 << 5) // y - static let hasIndices = RegExpFlags(rawValue: 1 << 6) // d - static let unicodeSets = RegExpFlags(rawValue: 1 << 7) // v + static let empty = RegExpFlags([]) + static let caseInsensitive = RegExpFlags(rawValue: 1 << 0) // i + static let global = RegExpFlags(rawValue: 1 << 1) // g + static let multiline = RegExpFlags(rawValue: 1 << 2) // m + static let dotall = RegExpFlags(rawValue: 1 << 3) // s + static let unicode = RegExpFlags(rawValue: 1 << 4) // u + static let sticky = RegExpFlags(rawValue: 1 << 5) // y + static let hasIndices = RegExpFlags(rawValue: 1 << 6) // d + static let unicodeSets = RegExpFlags(rawValue: 1 << 7) // v public static func random() -> RegExpFlags { - var flags = RegExpFlags(rawValue: UInt32.random(in: 0..<(1<<8))) + var flags = RegExpFlags(rawValue: UInt32.random(in: 0..<(1 << 8))) if flags.contains(.unicode) && flags.contains(.unicodeSets) { // clear one of them as they are mutually exclusive, they will throw a runtime exception if used together. - withEqualProbability({ - flags.subtract(.unicode) - }, { - flags.subtract(.unicodeSets) - }) + withEqualProbability( + { + flags.subtract(.unicode) + }, + { + flags.subtract(.unicodeSets) + }) } return flags } - private static let flagToCharDict: [RegExpFlags:String] = [ - .empty: "", + private static let flagToCharDict: [RegExpFlags: String] = [ + .empty: "", .caseInsensitive: "i", - .global: "g", - .multiline: "m", - .dotall: "s", - .unicode: "u", - .sticky: "y", - .hasIndices: "d", - .unicodeSets: "v", + .global: "g", + .multiline: "m", + .dotall: "s", + .unicode: "u", + .sticky: "y", + .hasIndices: "d", + .unicodeSets: "v", ] - static func |(lhs: RegExpFlags, rhs: RegExpFlags) -> RegExpFlags { + static func | (lhs: RegExpFlags, rhs: RegExpFlags) -> RegExpFlags { return RegExpFlags(rawValue: lhs.rawValue | rhs.rawValue) } } @@ -528,7 +559,6 @@ final class ObjectLiteralAddComputedProperty: JsOperation { } } - // A spread operation (e.g. `...v13,`) copying the properties from another object final class ObjectLiteralCopyProperties: JsOperation { override var opcode: Opcode { .objectLiteralCopyProperties(self) } @@ -557,7 +587,10 @@ final class BeginObjectLiteralMethod: BeginAnySubroutine { init(methodName: String, parameters: Parameters) { self.methodName = methodName // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -571,7 +604,10 @@ final class BeginObjectLiteralComputedMethod: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -588,7 +624,10 @@ final class BeginObjectLiteralGetter: BeginAnySubroutine { init(propertyName: String) { self.propertyName = propertyName // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 0), numInnerOutputs: 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -602,7 +641,10 @@ final class BeginObjectLiteralComputedGetter: BeginAnySubroutine { init() { // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -619,7 +661,10 @@ final class BeginObjectLiteralSetter: BeginAnySubroutine { init(propertyName: String) { self.propertyName = propertyName // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 1), numInnerOutputs: 2, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -633,7 +678,10 @@ final class BeginObjectLiteralComputedSetter: BeginAnySubroutine { init() { // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -707,7 +755,9 @@ final class BeginClassDefinition: JsOperation { init(hasSuperclass: Bool, isExpression: Bool) { self.hasSuperclass = hasSuperclass self.isExpression = isExpression - super.init(numInputs: hasSuperclass ? 1 : 0, numOutputs: 1, attributes: .isBlockStart, contextOpened: .classDefinition) + super.init( + numInputs: hasSuperclass ? 1 : 0, numOutputs: 1, attributes: .isBlockStart, + contextOpened: .classDefinition) } } @@ -716,7 +766,10 @@ final class BeginClassConstructor: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart, .isSingular], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart, .isSingular], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -736,7 +789,8 @@ final class ClassAddProperty: JsOperation { init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName self.isStatic = isStatic - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + super.init( + numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } @@ -752,7 +806,8 @@ final class ClassAddElement: JsOperation { init(index: Int64, hasValue: Bool, isStatic: Bool) { self.index = index self.isStatic = isStatic - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + super.init( + numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } @@ -780,7 +835,10 @@ final class BeginClassMethod: BeginAnySubroutine { self.methodName = methodName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -795,7 +853,10 @@ final class BeginClassComputedMethod: BeginAnySubroutine { init(parameters: Parameters, isStatic: Bool) { self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -813,7 +874,10 @@ final class BeginClassGetter: BeginAnySubroutine { self.propertyName = propertyName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 0), numInnerOutputs: 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -829,7 +893,10 @@ final class BeginClassComputedGetter: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -847,7 +914,10 @@ final class BeginClassSetter: BeginAnySubroutine { self.propertyName = propertyName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 1), numInnerOutputs: 2, + attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -863,7 +933,10 @@ final class BeginClassComputedSetter: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -877,7 +950,9 @@ final class BeginClassStaticInitializer: JsOperation { init() { // Inner output is the explicit |this| parameter // Static initializer blocks do not have .subroutine context as `return` is disallowed inside of them. - super.init(numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .method, .classMethod]) + super.init( + numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .method, .classMethod]) } } @@ -918,7 +993,10 @@ final class BeginClassPrivateMethod: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter. // See comment in ClassAddPrivateProperty for why this operation isn't mutable. - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -942,7 +1020,9 @@ final class CreateArray: JsOperation { } init(numInitialValues: Int) { - super.init(numInputs: numInitialValues, numOutputs: 1, firstVariadicInput: 0, attributes: [.isVariadic]) + super.init( + numInputs: numInitialValues, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isVariadic]) } } @@ -980,7 +1060,8 @@ final class CreateArrayWithSpread: JsOperation { if spreads.count > 0 { flags.insert(.isMutable) } - super.init(numInputs: spreads.count, numOutputs: 1, firstVariadicInput: 0, attributes: flags) + super.init( + numInputs: spreads.count, numOutputs: 1, firstVariadicInput: 0, attributes: flags) } } @@ -997,7 +1078,9 @@ final class CreateTemplateString: JsOperation { init(parts: [String]) { assert(parts.count > 0) self.parts = parts - super.init(numInputs: parts.count - 1, numOutputs: 1, firstVariadicInput: 0, attributes: [.isMutable, .isVariadic]) + super.init( + numInputs: parts.count - 1, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isMutable, .isVariadic]) } } @@ -1054,9 +1137,9 @@ public struct PropertyFlags: OptionSet { self.rawValue = rawValue } - static let writable = PropertyFlags(rawValue: 1 << 0) - static let configurable = PropertyFlags(rawValue: 1 << 1) - static let enumerable = PropertyFlags(rawValue: 1 << 2) + static let writable = PropertyFlags(rawValue: 1 << 0) + static let configurable = PropertyFlags(rawValue: 1 << 1) + static let enumerable = PropertyFlags(rawValue: 1 << 2) public static func random() -> PropertyFlags { return PropertyFlags(rawValue: UInt8.random(in: 0..<8)) @@ -1255,11 +1338,17 @@ public struct Parameters { class BeginAnySubroutine: JsOperation { let parameters: Parameters - init(parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, contextOpened: Context) { + init( + parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, + contextOpened: Context + ) { assert(contextOpened.contains(.subroutine)) assert(attributes.contains(.isBlockStart)) self.parameters = parameters - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -1274,11 +1363,12 @@ class EndAnySubroutine: JsOperation { // Functions beginnings are not considered mutable since it likely makes little sense to change things like the number of parameters. class BeginAnyFunction: BeginAnySubroutine { init(parameters: Parameters, contextOpened: Context = [.javascript, .subroutine]) { - super.init(parameters: parameters, - numInputs: 0, - numOutputs: 1, - numInnerOutputs: parameters.count, - contextOpened: contextOpened) + super.init( + parameters: parameters, + numInputs: 0, + numOutputs: 1, + numInnerOutputs: parameters.count, + contextOpened: contextOpened) } } class EndAnyFunction: EndAnySubroutine {} @@ -1292,7 +1382,10 @@ class BeginAnyNamedFunction: BeginAnyFunction { // lifter cannot guarantee that there are no name collisions with other named functions. let functionName: String? - init(parameters: Parameters, functionName: String?, contextOpened: Context = [.javascript, .subroutine]) { + init( + parameters: Parameters, functionName: String?, + contextOpened: Context = [.javascript, .subroutine] + ) { assert(functionName == nil || !functionName!.isEmpty) self.functionName = functionName super.init(parameters: parameters, contextOpened: contextOpened) @@ -1320,7 +1413,9 @@ final class BeginGeneratorFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginGeneratorFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .generatorFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .generatorFunction]) } } final class EndGeneratorFunction: EndAnyFunction { @@ -1332,7 +1427,9 @@ final class BeginAsyncFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginAsyncFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .asyncFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .asyncFunction]) } } final class EndAsyncFunction: EndAnyFunction { @@ -1344,7 +1441,8 @@ final class BeginAsyncArrowFunction: BeginAnyFunction { override var opcode: Opcode { .beginAsyncArrowFunction(self) } init(parameters: Parameters) { - super.init(parameters: parameters, contextOpened: [.javascript, .subroutine, .asyncFunction]) + super.init( + parameters: parameters, contextOpened: [.javascript, .subroutine, .asyncFunction]) } } final class EndAsyncArrowFunction: EndAnyFunction { @@ -1356,7 +1454,9 @@ final class BeginAsyncGeneratorFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginAsyncGeneratorFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .asyncFunction, .generatorFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .asyncFunction, .generatorFunction]) } } final class EndAsyncGeneratorFunction: EndAnyFunction { @@ -1370,7 +1470,9 @@ final class BeginConstructor: BeginAnySubroutine { override var opcode: Opcode { .beginConstructor(self) } init(parameters: Parameters) { - super.init(parameters: parameters, numOutputs: 1, numInnerOutputs: parameters.count + 1, contextOpened: [.javascript, .subroutine]) + super.init( + parameters: parameters, numOutputs: 1, numInnerOutputs: parameters.count + 1, + contextOpened: [.javascript, .subroutine]) } } final class EndConstructor: EndAnySubroutine { @@ -1412,7 +1514,9 @@ final class Return: JsOperation { } init(hasReturnValue: Bool) { - super.init(numInputs: hasReturnValue ? 1 : 0, attributes: [.isJump], requiredContext: [.javascript, .subroutine]) + super.init( + numInputs: hasReturnValue ? 1 : 0, attributes: [.isJump], + requiredContext: [.javascript, .subroutine]) } } @@ -1426,7 +1530,9 @@ final class Yield: JsOperation { } init(hasArgument: Bool) { - super.init(numInputs: hasArgument ? 1 : 0, numOutputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) + super.init( + numInputs: hasArgument ? 1 : 0, numOutputs: 1, attributes: [], + requiredContext: [.javascript, .generatorFunction]) } } @@ -1435,7 +1541,8 @@ final class YieldEach: JsOperation { override var opcode: Opcode { .yieldEach(self) } init() { - super.init(numInputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) + super.init( + numInputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) } } @@ -1443,7 +1550,9 @@ final class Await: JsOperation { override var opcode: Opcode { .await(self) } init() { - super.init(numInputs: 1, numOutputs: 1, attributes: [], requiredContext: [.javascript, .asyncFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [], + requiredContext: [.javascript, .asyncFunction]) } } @@ -1456,7 +1565,9 @@ final class CallFunction: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The called function is the first input. - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall]) } } @@ -1474,7 +1585,9 @@ final class CallFunctionWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The called function is the first input. - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall, .isMutable]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall, .isMutable]) } } @@ -1487,7 +1600,9 @@ final class Construct: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The constructor is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall]) } } @@ -1505,7 +1620,9 @@ final class ConstructWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The constructor is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall, .isMutable]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall, .isMutable]) } } @@ -1521,7 +1638,9 @@ final class CallMethod: GuardableOperation { init(methodName: String, numArguments: Int, isGuarded: Bool) { self.methodName = methodName // The reference object is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isMutable, .isVariadic, .isCall]) } } @@ -1541,7 +1660,9 @@ final class CallMethodWithSpread: GuardableOperation { self.methodName = methodName self.spreads = spreads // The reference object is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isMutable, .isVariadic, .isCall]) } } @@ -1554,7 +1675,9 @@ final class CallComputedMethod: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The reference object is the first input and the method name is the second input - super.init(isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, + attributes: [.isVariadic, .isCall]) } } @@ -1572,19 +1695,21 @@ final class CallComputedMethodWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The reference object is the first input and the method name is the second input - super.init(isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, + attributes: [.isMutable, .isVariadic, .isCall]) } } public enum UnaryOperator: String, CaseIterable { - case PreInc = "++" - case PreDec = "--" - case PostInc = "++ " // Raw value must be unique - case PostDec = "-- " // Raw value must be unique + case PreInc = "++" + case PreDec = "--" + case PostInc = "++ " // Raw value must be unique + case PostDec = "-- " // Raw value must be unique case LogicalNot = "!" case BitwiseNot = "~" - case Plus = "+" - case Minus = "-" + case Plus = "+" + case Minus = "-" var token: String { return self.rawValue.trimmingCharacters(in: [" "]) @@ -1611,19 +1736,19 @@ final class UnaryOperation: JsOperation { } public enum BinaryOperator: String, CaseIterable { - case Add = "+" - case Sub = "-" - case Mul = "*" - case Div = "/" - case Mod = "%" - case BitAnd = "&" - case BitOr = "|" + case Add = "+" + case Sub = "-" + case Mul = "*" + case Div = "/" + case Mod = "%" + case BitAnd = "&" + case BitOr = "|" case LogicAnd = "&&" - case LogicOr = "||" - case Xor = "^" - case LShift = "<<" - case RShift = ">>" - case Exp = "**" + case LogicOr = "||" + case Xor = "^" + case LShift = "<<" + case RShift = ">>" + case Exp = "**" case UnRShift = ">>>" // Nullish coalescing operator (??) case NullCoalesce = "??" @@ -1693,7 +1818,9 @@ final class DestructArray: JsOperation { init(indices: [Int64], lastIsRest: Bool) { assert(indices == indices.sorted(), "Indices must be sorted in ascending order") assert(indices.count == Set(indices).count, "Indices must not have duplicates") - assert(!lastIsRest || !indices.isEmpty, "DestructArray with lastIsRest requires at least one index") + assert( + !lastIsRest || !indices.isEmpty, + "DestructArray with lastIsRest requires at least one index") self.indices = indices self.lastIsRest = lastIsRest super.init(numInputs: 1, numOutputs: indices.count) @@ -1707,10 +1834,12 @@ final class DestructArrayAndReassign: JsOperation { let indices: [Int64] let lastIsRest: Bool - init(indices: [Int64], lastIsRest:Bool) { + init(indices: [Int64], lastIsRest: Bool) { assert(indices == indices.sorted(), "Indices must be sorted in ascending order") assert(indices.count == Set(indices).count, "Indices must not have duplicates") - assert(!lastIsRest || !indices.isEmpty, "DestructArray with lastIsRest requires at least one index") + assert( + !lastIsRest || !indices.isEmpty, + "DestructArray with lastIsRest requires at least one index") self.indices = indices self.lastIsRest = lastIsRest // The first input is the array being destructed @@ -1740,7 +1869,7 @@ final class DestructObjectAndReassign: JsOperation { let properties: [String] let hasRestElement: Bool - init(properties: [String], hasRestElement:Bool) { + init(properties: [String], hasRestElement: Bool) { self.properties = properties self.hasRestElement = hasRestElement // The first input is the object being destructed @@ -1750,13 +1879,13 @@ final class DestructObjectAndReassign: JsOperation { // This array must be kept in sync with the Comparator Enum in operations.proto public enum Comparator: String, CaseIterable { - case equal = "==" - case strictEqual = "===" - case notEqual = "!=" - case strictNotEqual = "!==" - case lessThan = "<" - case lessThanOrEqual = "<=" - case greaterThan = ">" + case equal = "==" + case strictEqual = "===" + case notEqual = "!=" + case strictNotEqual = "!==" + case lessThan = "<" + case lessThanOrEqual = "<=" + case greaterThan = ">" case greaterThanOrEqual = ">=" var token: String { @@ -1797,7 +1926,9 @@ final class BeginWith: JsOperation { override var opcode: Opcode { .beginWith(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript]) } } @@ -1817,7 +1948,9 @@ final class CallSuperConstructor: JsOperation { } init(numArguments: Int) { - super.init(numInputs: numArguments, firstVariadicInput: 0, attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .method]) + super.init( + numInputs: numArguments, firstVariadicInput: 0, attributes: [.isVariadic, .isCall], + requiredContext: [.javascript, .method]) } } @@ -1832,7 +1965,9 @@ final class CallSuperMethod: JsOperation { init(methodName: String, numArguments: Int) { self.methodName = methodName - super.init(numInputs: numArguments, numOutputs: 1, firstVariadicInput: 0, attributes: [.isCall, .isMutable, .isVariadic], requiredContext: [.javascript, .method]) + super.init( + numInputs: numArguments, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isCall, .isMutable, .isVariadic], requiredContext: [.javascript, .method]) } } @@ -1889,7 +2024,9 @@ final class CallPrivateMethod: JsOperation { self.methodName = methodName // The reference object is the first input. // See comment in GetPrivateProperty for why these aren't mutable. - super.init(numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .classMethod]) + super.init( + numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .classMethod]) } } @@ -1931,7 +2068,6 @@ final class GetComputedSuperProperty: JsOperation { } } - final class UpdateSuperProperty: JsOperation { override var opcode: Opcode { .updateSuperProperty(self) } @@ -1953,7 +2089,9 @@ final class BeginIf: JsOperation { init(inverted: Bool) { self.inverted = inverted - super.init(numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -1961,7 +2099,9 @@ final class BeginElse: JsOperation { override var opcode: Opcode { .beginElse(self) } init() { - super.init(attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2018,7 +2158,8 @@ final class BeginWhileLoopHeader: JsOperation { override var opcode: Opcode { .beginWhileLoopHeader(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2027,7 +2168,9 @@ final class BeginWhileLoopBody: JsOperation { override var opcode: Opcode { .beginWhileLoopBody(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2043,7 +2186,9 @@ final class BeginDoWhileLoopBody: JsOperation { override var opcode: Opcode { .beginDoWhileLoopBody(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2051,7 +2196,9 @@ final class BeginDoWhileLoopHeader: JsOperation { override var opcode: Opcode { .beginDoWhileLoopHeader(self) } init() { - super.init(attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2100,7 +2247,8 @@ final class BeginForLoopInitializer: JsOperation { override var opcode: Opcode { .beginForLoopInitializer(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2112,7 +2260,10 @@ final class BeginForLoopCondition: JsOperation { } init(numLoopVariables: Int) { - super.init(numInputs: numLoopVariables, numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: numLoopVariables, numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2124,7 +2275,10 @@ final class BeginForLoopAfterthought: JsOperation { } init(numLoopVariables: Int) { - super.init(numInputs: 1, numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: 1, numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2136,7 +2290,10 @@ final class BeginForLoopBody: JsOperation { } init(numLoopVariables: Int) { - super.init(numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2152,7 +2309,10 @@ final class BeginForInLoop: JsOperation { override var opcode: Opcode { .beginForInLoop(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2168,7 +2328,10 @@ final class BeginForOfLoop: JsOperation { override var opcode: Opcode { .beginForOfLoop(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2182,7 +2345,10 @@ final class BeginForOfLoopWithDestruct: JsOperation { assert(indices.count >= 1) self.indices = indices self.hasRestElement = hasRestElement - super.init(numInputs: 1, numInnerOutputs: indices.count, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: indices.count, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2210,7 +2376,10 @@ final class BeginRepeatLoop: JsOperation { init(iterations: Int, exposesLoopCounter: Bool = true) { self.iterations = iterations - super.init(numInnerOutputs: exposesLoopCounter ? 1 : 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInnerOutputs: exposesLoopCounter ? 1 : 0, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2250,7 +2419,9 @@ final class BeginCatch: JsOperation { override var opcode: Opcode { .beginCatch(self) } init() { - super.init(numInnerOutputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) + super.init( + numInnerOutputs: 1, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) } } @@ -2300,7 +2471,8 @@ final class BeginBlockStatement: JsOperation { override var opcode: Opcode { .beginBlockStatement(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2374,7 +2546,9 @@ final class BeginSwitchCase: JsOperation { override var opcode: Opcode { .beginSwitchCase(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .resumesSurroundingContext], requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .resumesSurroundingContext], + requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) } } @@ -2385,7 +2559,9 @@ final class BeginSwitchDefaultCase: JsOperation { override var opcode: Opcode { .beginSwitchDefaultCase(self) } init() { - super.init(attributes: [.isBlockStart, .resumesSurroundingContext, .isSingular], requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) + super.init( + attributes: [.isBlockStart, .resumesSurroundingContext, .isSingular], + requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) } } @@ -2429,7 +2605,9 @@ final class LoadNewTarget: JsOperation { final class BeginWasmModule: JsOperation { override var opcode: Opcode { .beginWasmModule(self) } init() { - super.init(numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], contextOpened: [.wasm]) + super.init( + numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], + contextOpened: [.wasm]) } } @@ -2476,7 +2654,8 @@ class BindFunction: JsOperation { override var opcode: Opcode { .bindFunction(self) } init(numInputs: Int) { - super.init(numInputs: numInputs, numOutputs: 1, firstVariadicInput: 1, + super.init( + numInputs: numInputs, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic], requiredContext: .javascript) } } @@ -2497,14 +2676,14 @@ class CreateWasmGlobal: JsOperation { // This instruction is used to create strongly typed WasmMemories in the JS world that can be imported by a WasmModule. class CreateWasmMemory: JsOperation { - override var opcode: Opcode { .createWasmMemory(self) } + override var opcode: Opcode { .createWasmMemory(self) } - let memType: WasmMemoryType + let memType: WasmMemoryType - init(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) { - self.memType = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) - super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) - } + init(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) { + self.memType = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) + super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) + } } // This instruction is used to create strongly typed WasmTables in the JS world that can be imported by a WasmModule. @@ -2515,7 +2694,8 @@ class CreateWasmTable: JsOperation { let tableType: WasmTableType init(elementType: ILType, limits: Limits, isTable64: Bool) { - self.tableType = WasmTableType(elementType: elementType, limits: limits, isTable64: isTable64, knownEntries: []) + self.tableType = WasmTableType( + elementType: elementType, limits: limits, isTable64: isTable64, knownEntries: []) super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) } } @@ -2538,13 +2718,14 @@ class CreateWasmTag: JsOperation { } } -class WasmTypeOperation : Operation {} +class WasmTypeOperation: Operation {} class WasmBeginTypeGroup: WasmTypeOperation { override var opcode: Opcode { .wasmBeginTypeGroup(self) } init() { - super.init(attributes: [.isBlockStart], requiredContext: [.javascript], - contextOpened: [.wasmTypeGroup]) + super.init( + attributes: [.isBlockStart], requiredContext: [.javascript], + contextOpened: [.wasmTypeGroup]) } } @@ -2555,21 +2736,24 @@ class WasmEndTypeGroup: WasmTypeOperation { } init(typesCount: Int) { - super.init(numInputs: typesCount, numOutputs: typesCount, firstVariadicInput: 0, - attributes: [.isBlockEnd, .resumesSurroundingContext, .isVariadic, .isNotInputMutable], - requiredContext: [.wasmTypeGroup]) + super.init( + numInputs: typesCount, numOutputs: typesCount, firstVariadicInput: 0, + attributes: [.isBlockEnd, .resumesSurroundingContext, .isVariadic, .isNotInputMutable], + requiredContext: [.wasmTypeGroup]) } } class WasmDefineArrayType: WasmTypeOperation { override var opcode: Opcode { .wasmDefineArrayType(self) } - let elementType : ILType + let elementType: ILType let mutability: Bool init(elementType: ILType, mutability: Bool) { self.elementType = elementType self.mutability = mutability - super.init(numInputs: elementType.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmTypeGroup]) + super.init( + numInputs: elementType.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmTypeGroup]) } } @@ -2594,7 +2778,8 @@ class WasmDefineSignatureType: WasmTypeOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasmTypeGroup]) } } @@ -2644,7 +2829,9 @@ final class Explore: JsInternalOperation { init(id: String, numArguments: Int, rngSeed: UInt32) { // IDs should be valid JavaScript property names since they will typically be used in that way. - assert(id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) && id.contains(where: { $0.isLetter })) + assert( + id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) + && id.contains(where: { $0.isLetter })) self.id = id self.rngSeed = rngSeed @@ -2661,7 +2848,9 @@ final class Probe: JsInternalOperation { init(id: String) { // IDs should be valid JavaScript property names since they will typically be used in that way. - assert(id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) && id.contains(where: { $0.isLetter })) + assert( + id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) + && id.contains(where: { $0.isLetter })) self.id = id super.init(numInputs: 1) @@ -2685,7 +2874,8 @@ final class Fixup: JsInternalOperation { return numOutputs == 1 } - init(id: String, action: String, originalOperation: String, numArguments: Int, hasOutput: Bool) { + init(id: String, action: String, originalOperation: String, numArguments: Int, hasOutput: Bool) + { self.id = id self.action = action self.originalOperation = originalOperation diff --git a/Sources/Fuzzilli/FuzzIL/Operation.swift b/Sources/Fuzzilli/FuzzIL/Operation.swift index 6d5e12860..2a4f9b910 100644 --- a/Sources/Fuzzilli/FuzzIL/Operation.swift +++ b/Sources/Fuzzilli/FuzzIL/Operation.swift @@ -58,7 +58,11 @@ public class Operation { fatalError("Operations must override the opcode getter. \(self.name) does not") } - init(numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .empty, contextOpened: Context = .empty) { + init( + numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .empty, contextOpened: Context = .empty + ) { assert(attributes.contains(.isVariadic) == (firstVariadicInput != -1)) assert(firstVariadicInput == -1 || firstVariadicInput <= numInputs) assert(contextOpened == .empty || attributes.contains(.isBlockStart)) @@ -87,28 +91,28 @@ public class Operation { // is the isStrict member of function definitions: the value space is two // (true or false) and mutating the isStrict member is probably not very // interesting compared to mutations on other operations. - static let isMutable = Attributes(rawValue: 1 << 0) + static let isMutable = Attributes(rawValue: 1 << 0) // The operation performs a subroutine call. - static let isCall = Attributes(rawValue: 1 << 1) + static let isCall = Attributes(rawValue: 1 << 1) // The operation is the start of a block. - static let isBlockStart = Attributes(rawValue: 1 << 2) + static let isBlockStart = Attributes(rawValue: 1 << 2) // The operation is the end of a block. - static let isBlockEnd = Attributes(rawValue: 1 << 3) + static let isBlockEnd = Attributes(rawValue: 1 << 3) // The operation is used for internal purposes and should not // be visible to the user (e.g. appear in emitted samples). - static let isInternal = Attributes(rawValue: 1 << 4) + static let isInternal = Attributes(rawValue: 1 << 4) // The operation behaves like an (unconditional) jump. Any // code until the next block end is therefore dead code. - static let isJump = Attributes(rawValue: 1 << 5) + static let isJump = Attributes(rawValue: 1 << 5) // The operation can take a variable number of inputs. // The firstVariadicInput contains the index of the first variadic input. - static let isVariadic = Attributes(rawValue: 1 << 6) + static let isVariadic = Attributes(rawValue: 1 << 6) // This operation should occur at most once in its surrounding context. // If there are multiple singular operations in the same context, then @@ -119,7 +123,7 @@ public class Operation { // block instead of ignoring all but the first one. However, that would // complicate code generation and splicing which cannot generally // uphold this property. - static let isSingular = Attributes(rawValue: 1 << 7) + static let isSingular = Attributes(rawValue: 1 << 7) // The operation propagates the surrounding context. // Most control-flow operations keep their surrounding context active. @@ -127,15 +131,15 @@ public class Operation { // The instruction resumes the context from before its parent context. // This is useful for example for BeginSwitch and BeginSwitchCase. - static let resumesSurroundingContext = Attributes(rawValue: 1 << 9) + static let resumesSurroundingContext = Attributes(rawValue: 1 << 9) // The instruction is a Nop operation. - static let isNop = Attributes(rawValue: 1 << 10) + static let isNop = Attributes(rawValue: 1 << 10) // The instruction cannot be mutated with the input mutator // This is not the case for most instructions except wasm instructions where we need to // preserve types for correctness. Note: this is different than the .isMutable attribute. - static let isNotInputMutable = Attributes(rawValue: 1 << 11) + static let isNotInputMutable = Attributes(rawValue: 1 << 11) } } @@ -154,7 +158,6 @@ final class Nop: Operation { } } - // Expose the name of an operation as instance and class variable extension Operation { var name: String { diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index b8c8bec2e..9b2c81122 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -59,7 +59,10 @@ public final class Program: CustomStringConvertible { } /// Construct a program with the given code and type information. - public convenience init(code: Code, parent: Program? = nil, comments: ProgramComments = ProgramComments(), contributors: Contributors = Contributors()) { + public convenience init( + code: Code, parent: Program? = nil, comments: ProgramComments = ProgramComments(), + contributors: Contributors = Contributors() + ) { // We should never see instructions with set flags here, as Flags are currently only used temporarily (e.g. Minimizer) assert(code.allSatisfy { instr in instr.flags == Instruction.Flags.empty }) self.init(with: code) @@ -151,14 +154,16 @@ extension Program: ProtobufConvertible { do { code.append(try Instruction(from: protoInstr, with: opCache)) } catch FuzzilliError.instructionDecodingError(let reason) { - throw FuzzilliError.programDecodingError("could not decode instruction #\(i): \(reason)") + throw FuzzilliError.programDecodingError( + "could not decode instruction #\(i): \(reason)") } } do { try code.check() } catch FuzzilliError.codeVerificationError(let reason) { - throw FuzzilliError.programDecodingError("decoded code is not statically valid: \(reason)") + throw FuzzilliError.programDecodingError( + "decoded code is not statically valid: \(reason)") } self.init(code: code) diff --git a/Sources/Fuzzilli/FuzzIL/ProgramComments.swift b/Sources/Fuzzilli/FuzzIL/ProgramComments.swift index 90a9dfd97..e53e14fc9 100644 --- a/Sources/Fuzzilli/FuzzIL/ProgramComments.swift +++ b/Sources/Fuzzilli/FuzzIL/ProgramComments.swift @@ -37,7 +37,7 @@ public struct ProgramComments { } } - private var comments: [Int32:String] = [:] + private var comments: [Int32: String] = [:] public init() {} diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index 567d58756..f8a60233c 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - // Miscellaneous semantics of FuzzIL. Also see JSTyper for execution semantics of operations. extension Operation { @@ -24,20 +23,20 @@ extension Operation { switch opcode { case .callFunction, - .callMethod, - .callComputedMethod: - // We assume that a constructor doesn't modify its arguments when called. + .callMethod, + .callComputedMethod: + // We assume that a constructor doesn't modify its arguments when called. return true case .setProperty, - .updateProperty, - .setElement, - .updateElement, - .setComputedProperty, - .updateComputedProperty, - .yield, - .deleteProperty, - .deleteComputedProperty, - .deleteElement: + .updateProperty, + .setElement, + .updateElement, + .setComputedProperty, + .updateComputedProperty, + .yield, + .deleteProperty, + .deleteComputedProperty, + .deleteElement: return inputIdx == 0 default: return false @@ -47,12 +46,12 @@ extension Operation { func reassigns(input inputIdx: Int) -> Bool { switch opcode { case .reassign, - .update: + .update: return inputIdx == 0 case .unaryOperation(let op): return op.op.reassignsInput case .destructArrayAndReassign, - .destructObjectAndReassign: + .destructObjectAndReassign: return inputIdx != 0 default: return false @@ -117,7 +116,7 @@ extension Instruction { case (.loadNull, .loadNull): canFold = true case (.loadRegExp(let op1), .loadRegExp(let op2)): - canFold = op1.pattern == op2.pattern && op1.flags == op2.flags + canFold = op1.pattern == op2.pattern && op1.flags == op2.flags default: assert(self.op.name != other.op.name) } @@ -145,7 +144,7 @@ extension Operation { case .beginObjectLiteralComputedSetter: return endOp is EndObjectLiteralComputedSetter case .beginClassDefinition: - return endOp is EndClassDefinition + return endOp is EndClassDefinition case .beginClassConstructor: return endOp is EndClassConstructor case .beginClassMethod: @@ -187,7 +186,7 @@ extension Operation { case .beginSwitch: return endOp is EndSwitch case .beginSwitchCase, - .beginSwitchDefaultCase: + .beginSwitchDefaultCase: return endOp is EndSwitchCase case .beginWhileLoopHeader: return endOp is BeginWhileLoopBody @@ -208,7 +207,7 @@ extension Operation { case .beginForInLoop: return endOp is EndForInLoop case .beginForOfLoop, - .beginForOfLoopWithDestruct: + .beginForOfLoopWithDestruct: return endOp is EndForOfLoop case .beginRepeatLoop: return endOp is EndRepeatLoop @@ -233,7 +232,7 @@ extension Operation { case .wasmBeginTryTable: return endOp is WasmEndTryTable case .wasmBeginTry, - .wasmBeginCatch: + .wasmBeginCatch: return endOp is WasmEndTry || endOp is WasmBeginCatch || endOp is WasmBeginCatchAll case .wasmBeginCatchAll: return endOp is WasmEndTry diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index b463f8432..2fc55cec3 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -112,34 +112,34 @@ public struct ILType: Hashable { public static let undefined = ILType(definiteType: .undefined) /// An integer type. - public static let integer = ILType(definiteType: .integer) + public static let integer = ILType(definiteType: .integer) /// A bigInt type. - public static let bigint = ILType(definiteType: .bigint) + public static let bigint = ILType(definiteType: .bigint) /// A floating point number. - public static let float = ILType(definiteType: .float) + public static let float = ILType(definiteType: .float) /// A string. - public static let string = ILType(definiteType: .string) + public static let string = ILType(definiteType: .string) /// A boolean. - public static let boolean = ILType(definiteType: .boolean) + public static let boolean = ILType(definiteType: .boolean) /// A RegExp - public static let regexp = ILType(definiteType: .regexp) + public static let regexp = ILType(definiteType: .regexp) /// A type that can be iterated over, such as an array or a generator. - public static let iterable = ILType(definiteType: .iterable) + public static let iterable = ILType(definiteType: .iterable) /// The type that subsumes all others (in js). - public static let jsAnything = ILType(definiteType: .nothing, possibleType: .jsAnything) + public static let jsAnything = ILType(definiteType: .nothing, possibleType: .jsAnything) /// The type that subsumes all others (in wasm). - public static let wasmAnything = ILType(definiteType: .nothing, possibleType: .wasmAnything) + public static let wasmAnything = ILType(definiteType: .nothing, possibleType: .wasmAnything) /// The type that is subsumed by all others. - public static let nothing = ILType(definiteType: .nothing, possibleType: .nothing) + public static let nothing = ILType(definiteType: .nothing, possibleType: .nothing) /// A number: either an integer or a float. public static let number: ILType = .integer | .float @@ -151,14 +151,20 @@ public struct ILType: Hashable { public static let nullish: ILType = .undefined /// Constructs an object type. - public static func object(ofGroup group: String? = nil, withProperties properties: [String] = [], withMethods methods: [String] = [], withWasmType wasmExt: WasmTypeExtension? = nil) -> ILType { - let ext = TypeExtension(group: group, properties: Set(properties), methods: Set(methods), signature: nil, wasmExt: wasmExt) + public static func object( + ofGroup group: String? = nil, withProperties properties: [String] = [], + withMethods methods: [String] = [], withWasmType wasmExt: WasmTypeExtension? = nil + ) -> ILType { + let ext = TypeExtension( + group: group, properties: Set(properties), methods: Set(methods), signature: nil, + wasmExt: wasmExt) return ILType(definiteType: .object, ext: ext) } /// Constructs an enum type, which is a string with a limited set of allowed values. public static func enumeration(ofName name: String, withValues values: [String]) -> ILType { - let ext = TypeExtension(group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) + let ext = TypeExtension( + group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) return ILType(definiteType: .string, ext: ext) } @@ -167,7 +173,8 @@ public struct ILType: Hashable { /// Most code will treat these as strings, but the JavaScriptEnvironment can register /// producingGenerators for them so they can be generated more intelligently. public static func namedString(ofName name: String) -> ILType { - let ext = TypeExtension(group: name, properties: Set(), methods: Set(), signature: nil, wasmExt: nil) + let ext = TypeExtension( + group: name, properties: Set(), methods: Set(), signature: nil, wasmExt: nil) return ILType(definiteType: .string, ext: ext) } @@ -194,8 +201,11 @@ public struct ILType: Hashable { /// An unbound function. This is a function with this === null which requires to get a this /// bound (e.g. via .bind(), .call() or .apply()). - public static func unboundFunction(_ signature: Signature? = nil, receiver: ILType? = nil) -> ILType { - let ext = TypeExtension(properties: Set(), methods: Set(), signature: signature, receiver: receiver) + public static func unboundFunction(_ signature: Signature? = nil, receiver: ILType? = nil) + -> ILType + { + let ext = TypeExtension( + properties: Set(), methods: Set(), signature: signature, receiver: receiver) return ILType(definiteType: [.unboundFunction], ext: ext) } @@ -203,38 +213,59 @@ public struct ILType: Hashable { // This type is used to indicate block labels in wasm. public static func label(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { - return ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) + return ILType( + definiteType: .label, + ext: TypeExtension( + group: "WasmLabel", properties: [], methods: [], signature: nil, + wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) } - public static let anyLabel: ILType = ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) + public static let anyLabel: ILType = ILType( + definiteType: .label, + ext: TypeExtension( + group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) /// A label that allows rethrowing the caught exception of a catch block. public static let exceptionLabel: ILType = ILType(definiteType: .exceptionLabel) - public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) -> ILType { + public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) + -> ILType + { let wasmMemExt = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) - return .object(ofGroup: "WasmMemory", withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"], withWasmType: wasmMemExt) + return .object( + ofGroup: "WasmMemory", withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"], + withWasmType: wasmMemExt) } - public static func wasmDataSegment(segmentLength: Int? = nil) -> ILType { + public static func wasmDataSegment(segmentLength: Int? = nil) -> ILType { let maybeWasmExtention = segmentLength.map { WasmDataSegmentType(segmentLength: $0) } - let typeExtension = TypeExtension(group: "WasmDataSegment", properties: Set(), methods: Set(), signature: nil, wasmExt: maybeWasmExtention) + let typeExtension = TypeExtension( + group: "WasmDataSegment", properties: Set(), methods: Set(), signature: nil, + wasmExt: maybeWasmExtention) return ILType(definiteType: .wasmDataSegment, ext: typeExtension) } - public static func wasmElementSegment(segmentLength: Int? = nil) -> ILType { + public static func wasmElementSegment(segmentLength: Int? = nil) -> ILType { let maybeWasmExtention = segmentLength.map { WasmElementSegmentType(segmentLength: $0) } - let typeExtension = TypeExtension(group: "WasmElementSegment", properties: Set(), methods: Set(), signature: nil, wasmExt: maybeWasmExtention) + let typeExtension = TypeExtension( + group: "WasmElementSegment", properties: Set(), methods: Set(), signature: nil, + wasmExt: maybeWasmExtention) return ILType(definiteType: .wasmElementSegment, ext: typeExtension) } public static func wasmTable(wasmTableType: WasmTableType) -> ILType { - return .object(ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"], withWasmType: wasmTableType) + return .object( + ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"], + withWasmType: wasmTableType) } public static func wasmFunctionDef(_ signature: WasmSignature? = nil) -> ILType { - return ILType(definiteType: .wasmFunctionDef, - ext: TypeExtension(properties: Set(), methods: Set(), signature: nil, wasmExt: WasmFunctionDefinition(signature))) + return ILType( + definiteType: .wasmFunctionDef, + ext: TypeExtension( + properties: Set(), methods: Set(), signature: nil, + wasmExt: WasmFunctionDefinition(signature))) } // @@ -247,20 +278,48 @@ public struct ILType: Hashable { public static let wasmi64 = ILType(definiteType: .wasmi64) public static let wasmf32 = ILType(definiteType: .wasmf32) public static let wasmf64 = ILType(definiteType: .wasmf64) - public static func wasmExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: true) } - public static func wasmRefExtern(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: false) } - public static func wasmFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmFunc, shared: shared, nullability: true) } - public static func wasmExnRef(shared: Bool = false) -> ILType { wasmRef(.WasmExn, shared: shared, nullability: true) } - public static func wasmI31Ref(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: true) } - public static func wasmRefI31(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: false) } - public static func wasmAnyRef(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: true) } - public static func wasmRefAny(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: false) } - public static func wasmNullRef(shared: Bool = false) -> ILType { wasmRef(.WasmNone, shared: shared, nullability: true) } - public static func wasmNullExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoExtern, shared: shared, nullability: true) } - public static func wasmNullFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoFunc, shared: shared, nullability: true) } - public static func wasmEqRef(shared: Bool = false) -> ILType { wasmRef(.WasmEq, shared: shared, nullability: true) } - public static func wasmStructRef(shared: Bool = false) -> ILType { wasmRef(.WasmStruct, shared: shared, nullability: true) } - public static func wasmArrayRef(shared: Bool = false) -> ILType { wasmRef(.WasmArray, shared: shared, nullability: true) } + public static func wasmExternRef(shared: Bool = false) -> ILType { + wasmRef(.WasmExtern, shared: shared, nullability: true) + } + public static func wasmRefExtern(shared: Bool = false) -> ILType { + wasmRef(.WasmExtern, shared: shared, nullability: false) + } + public static func wasmFuncRef(shared: Bool = false) -> ILType { + wasmRef(.WasmFunc, shared: shared, nullability: true) + } + public static func wasmExnRef(shared: Bool = false) -> ILType { + wasmRef(.WasmExn, shared: shared, nullability: true) + } + public static func wasmI31Ref(shared: Bool = false) -> ILType { + wasmRef(.WasmI31, shared: shared, nullability: true) + } + public static func wasmRefI31(shared: Bool = false) -> ILType { + wasmRef(.WasmI31, shared: shared, nullability: false) + } + public static func wasmAnyRef(shared: Bool = false) -> ILType { + wasmRef(.WasmAny, shared: shared, nullability: true) + } + public static func wasmRefAny(shared: Bool = false) -> ILType { + wasmRef(.WasmAny, shared: shared, nullability: false) + } + public static func wasmNullRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNone, shared: shared, nullability: true) + } + public static func wasmNullExternRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNoExtern, shared: shared, nullability: true) + } + public static func wasmNullFuncRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNoFunc, shared: shared, nullability: true) + } + public static func wasmEqRef(shared: Bool = false) -> ILType { + wasmRef(.WasmEq, shared: shared, nullability: true) + } + public static func wasmStructRef(shared: Bool = false) -> ILType { + wasmRef(.WasmStruct, shared: shared, nullability: true) + } + public static func wasmArrayRef(shared: Bool = false) -> ILType { + wasmRef(.WasmArray, shared: shared, nullability: true) + } public static let wasmSimd128 = ILType(definiteType: .wasmSimd128) public static let wasmGenericRef = ILType(definiteType: .wasmRef) @@ -277,22 +336,28 @@ public struct ILType: Hashable { static func wasmTypeDef(description: WasmTypeDescription? = nil) -> ILType { let typeDef = WasmTypeDefinition() typeDef.description = description - return ILType(definiteType: .wasmTypeDef, ext: TypeExtension( - properties: [], methods: [], signature: nil, wasmExt: typeDef)) + return ILType( + definiteType: .wasmTypeDef, + ext: TypeExtension( + properties: [], methods: [], signature: nil, wasmExt: typeDef)) } static func wasmSelfReference() -> ILType { wasmTypeDef(description: .selfReference) } - static func wasmRef(_ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true) -> ILType { + static func wasmRef( + _ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true + ) -> ILType { .wasmRef(.Abstract(.init(heapType, shared: shared)), nullability: nullability) } static func wasmRef(_ kind: WasmReferenceType.Kind, nullability: Bool) -> ILType { - return ILType(definiteType: .wasmRef, ext: TypeExtension( - properties: [], methods: [], signature: nil, - wasmExt: WasmReferenceType(kind, nullability: nullability))) + return ILType( + definiteType: .wasmRef, + ext: TypeExtension( + properties: [], methods: [], signature: nil, + wasmExt: WasmReferenceType(kind, nullability: nullability))) } static func wasmIndexRef(_ desc: WasmTypeDescription, nullability: Bool) -> ILType { @@ -300,7 +365,8 @@ public struct ILType: Hashable { } // The union of all primitive wasm types - public static let wasmPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef + public static let wasmPrimitive = + .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef public static let wasmNumericalPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 @@ -332,10 +398,11 @@ public struct ILType: Hashable { return ILType(definiteType: definiteType) } - public static func ==(lhs: ILType, rhs: ILType) -> Bool { - return lhs.definiteType == rhs.definiteType && lhs.possibleType == rhs.possibleType && lhs.ext == rhs.ext + public static func == (lhs: ILType, rhs: ILType) -> Bool { + return lhs.definiteType == rhs.definiteType && lhs.possibleType == rhs.possibleType + && lhs.ext == rhs.ext } - public static func !=(lhs: ILType, rhs: ILType) -> Bool { + public static func != (lhs: ILType, rhs: ILType) -> Bool { return !(lhs == rhs) } @@ -394,13 +461,18 @@ public struct ILType: Hashable { if isUnion { // Verify that either the other definite type is empty or that there is some overlap between // our possible type and the other definite type - guard other.definiteType.isEmpty || !other.definiteType.intersection(self.possibleType).isEmpty else { + guard + other.definiteType.isEmpty + || !other.definiteType.intersection(self.possibleType).isEmpty + else { return false } // Given the above, we can subtract the other's definite type here from its possible type so that // e.g. StringObjects are correctly subsumed by both .string and .object. - guard self.possibleType.isSuperset(of: other.possibleType.subtracting(other.definiteType)) else { + guard + self.possibleType.isSuperset(of: other.possibleType.subtracting(other.definiteType)) + else { return false } } @@ -424,7 +496,8 @@ public struct ILType: Hashable { } // Either our type must be a generic callable without a signature, or our signature must subsume the other type's signature. - guard signature == nil || (other.signature != nil && signature!.subsumes(other.signature!)) else { + guard signature == nil || (other.signature != nil && signature!.subsumes(other.signature!)) + else { return false } @@ -437,13 +510,17 @@ public struct ILType: Hashable { return false } - guard receiver == nil || (other.receiver != nil && receiver!.subsumes(other.receiver!)) else { + guard receiver == nil || (other.receiver != nil && receiver!.subsumes(other.receiver!)) + else { return false } // Wasm type extension. - guard !self.hasWasmTypeInfo || (other.hasWasmTypeInfo - && self.wasmType!.subsumes(other.wasmType!)) else { + guard + !self.hasWasmTypeInfo + || (other.hasWasmTypeInfo + && self.wasmType!.subsumes(other.wasmType!)) + else { return false } @@ -463,15 +540,27 @@ public struct ILType: Hashable { // If you add a new custom object group, please check the logic below. // Make sure that the groups themselves are not prefixes. - assert(JSTyper.ObjectGroupManager.ObjectGroupType.allCases == [.wasmModule, .wasmExports, .objectLiteral, .jsClass]) + assert( + JSTyper.ObjectGroupManager.ObjectGroupType.allCases == [ + .wasmModule, .wasmExports, .objectLiteral, .jsClass, + ]) - let objectGroupTypes = ["_fuzz_Object", "_fuzz_WasmModule", "_fuzz_WasmExports", "_fuzz_Class", "_fuzz_Constructor"] + let objectGroupTypes = [ + "_fuzz_Object", "_fuzz_WasmModule", "_fuzz_WasmExports", "_fuzz_Class", + "_fuzz_Constructor", + ] for groupType in objectGroupTypes { if rhs.hasPrefix(groupType) && lhs.hasPrefix(groupType) { // Check that they differ only in a number at the end. - assert(rhs.range(of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil) != nil && - lhs.range(of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil) != nil) + assert( + rhs.range( + of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil + ) != nil + && lhs.range( + of: "\(groupType)\\d+", options: .regularExpression, range: nil, + locale: nil) != nil + ) return true } } @@ -479,15 +568,14 @@ public struct ILType: Hashable { return false } - public static func >=(lhs: ILType, rhs: ILType) -> Bool { + public static func >= (lhs: ILType, rhs: ILType) -> Bool { return lhs.subsumes(rhs) } - public static func <=(lhs: ILType, rhs: ILType) -> Bool { + public static func <= (lhs: ILType, rhs: ILType) -> Bool { return rhs.subsumes(lhs) } - // // Access to extended type data // @@ -544,7 +632,6 @@ public struct ILType: Hashable { return wasmMemoryType != nil && ext?.group == "WasmMemory" } - public var wasmDataSegmentType: WasmDataSegmentType? { return ext?.wasmExt as? WasmDataSegmentType } @@ -561,7 +648,6 @@ public struct ILType: Hashable { return wasmElementSegmentType != nil } - public var wasmTableType: WasmTableType? { return ext?.wasmExt as? WasmTableType } @@ -659,8 +745,8 @@ public struct ILType: Hashable { public func requiredInputCount() -> Int { if let ref = wasmReferenceType { switch ref.kind { - case .Index: return 1 - case .Abstract: return 0 + case .Index: return 1 + case .Abstract: return 0 } } return 0 @@ -675,7 +761,6 @@ public struct ILType: Hashable { return isPacked() ? .wasmi32 : self } - // // Type operations // @@ -692,13 +777,17 @@ public struct ILType: Hashable { /// WasmTypeExtensions (currently WasmReferenceType), there are more complex union rules. public func union(with other: ILType) -> ILType { // Trivial cases. - if self == .jsAnything && other.Is(.jsAnything) || other == .jsAnything && self.Is(.jsAnything) { + if self == .jsAnything && other.Is(.jsAnything) + || other == .jsAnything && self.Is(.jsAnything) + { return .jsAnything } else if self == .nothing { return other } else if other == .nothing { return self - } else if self == .wasmAnything && other.Is(.wasmAnything) || other == .wasmAnything && self.Is(.wasmAnything) { + } else if self == .wasmAnything && other.Is(.wasmAnything) + || other == .wasmAnything && self.Is(.wasmAnything) + { return .wasmAnything } @@ -717,10 +806,13 @@ public struct ILType: Hashable { // that means finding the set of shared properties and methods, which is imprecise but correct. let commonProperties = self.properties.intersection(other.properties) let commonMethods = self.methods.intersection(other.methods) - let signature = self.signature == other.signature ? self.signature : nil // TODO: this is overly coarse, we could also see if one signature subsumes the other, then take the subsuming one. - let receiver = other.receiver != nil ? self.receiver?.intersection(with: other.receiver!) : nil + let signature = self.signature == other.signature ? self.signature : nil // TODO: this is overly coarse, we could also see if one signature subsumes the other, then take the subsuming one. + let receiver = + other.receiver != nil ? self.receiver?.intersection(with: other.receiver!) : nil var group = self.group == other.group ? self.group : nil - let wasmExt = self.wasmType != nil && other.wasmType != nil ? self.wasmType!.union(other.wasmType!) : nil + let wasmExt = + self.wasmType != nil && other.wasmType != nil + ? self.wasmType!.union(other.wasmType!) : nil // Object groups are used to describe certain wasm types. If the WasmTypeExtension is lost, // the group should also be invalidated. This ensures that e.g. any // `.object(ofGroup: "WasmTag")` always has a `.wasmTagType` extension. @@ -728,14 +820,18 @@ public struct ILType: Hashable { group = nil } - return ILType(definiteType: definiteType, possibleType: possibleType, ext: TypeExtension(group: group, properties: commonProperties, methods: commonMethods, signature: signature, wasmExt: wasmExt, receiver: receiver)) + return ILType( + definiteType: definiteType, possibleType: possibleType, + ext: TypeExtension( + group: group, properties: commonProperties, methods: commonMethods, + signature: signature, wasmExt: wasmExt, receiver: receiver)) } - public static func |(lhs: ILType, rhs: ILType) -> ILType { + public static func | (lhs: ILType, rhs: ILType) -> ILType { return lhs.union(with: rhs) } - public static func |=(lhs: inout ILType, rhs: ILType) { + public static func |= (lhs: inout ILType, rhs: ILType) { lhs = lhs | rhs } @@ -794,39 +890,52 @@ public struct ILType: Hashable { // For signatures we take a shortcut: if one signature subsumes the other, then the intersection // must be the subsumed signature. Additionally, we know that if there is an intersection, the // return value must be the intersection of the return values, so we can compute that up-front. - let returnValue = (self.signature?.outputType ?? .jsAnything) & (other.signature?.outputType ?? .jsAnything) + let returnValue = + (self.signature?.outputType ?? .jsAnything) + & (other.signature?.outputType ?? .jsAnything) guard returnValue != .nothing else { return .nothing } let ourSignature = self.signature?.replacingOutputType(with: returnValue) let otherSignature = other.signature?.replacingOutputType(with: returnValue) let signature: Signature? - if ourSignature == nil || (otherSignature != nil && ourSignature!.subsumes(otherSignature!)) { + if ourSignature == nil || (otherSignature != nil && ourSignature!.subsumes(otherSignature!)) + { signature = otherSignature - } else if otherSignature == nil || (ourSignature != nil && otherSignature!.subsumes(ourSignature!)) { + } else if otherSignature == nil + || (ourSignature != nil && otherSignature!.subsumes(ourSignature!)) + { signature = ourSignature } else { return .nothing } - let receiver = self.receiver != nil && other.receiver != nil ? self.receiver!.union(with: other.receiver!) : self.receiver ?? other.receiver + let receiver = + self.receiver != nil && other.receiver != nil + ? self.receiver!.union(with: other.receiver!) : self.receiver ?? other.receiver // If either value is nil, the result is the non-nil value. If both are non-nil, the result // is their intersection if valid, otherwise .nothing is returned. var wasmExt: WasmTypeExtension? = self.wasmType ?? other.wasmType if self.wasmType != nil && other.wasmType != nil { - guard let wasmIntersection = self.wasmType!.intersection(other.wasmType!) else { return .nothing } + guard let wasmIntersection = self.wasmType!.intersection(other.wasmType!) else { + return .nothing + } wasmExt = wasmIntersection } - return ILType(definiteType: definiteType, possibleType: possibleType, ext: TypeExtension(group: group, properties: properties, methods: methods, signature: signature, wasmExt: wasmExt, receiver: receiver)) + return ILType( + definiteType: definiteType, possibleType: possibleType, + ext: TypeExtension( + group: group, properties: properties, methods: methods, signature: signature, + wasmExt: wasmExt, receiver: receiver)) } - public static func &(lhs: ILType, rhs: ILType) -> ILType { + public static func & (lhs: ILType, rhs: ILType) -> ILType { return lhs.intersection(with: rhs) } - public static func &=(lhs: inout ILType, rhs: ILType) { + public static func &= (lhs: inout ILType, rhs: ILType) { lhs = lhs & rhs } @@ -838,12 +947,14 @@ public struct ILType: Hashable { } // Merging of callables with different signatures is not allowed. - guard self.signature == nil || other.signature == nil || self.signature == other.signature else { + guard self.signature == nil || other.signature == nil || self.signature == other.signature + else { return false } // Merging of unbound fucntions with different receivers is not allowed. - guard self.receiver == nil || other.receiver == nil || self.receiver == other.receiver else { + guard self.receiver == nil || other.receiver == nil || self.receiver == other.receiver + else { return false } @@ -858,7 +969,10 @@ public struct ILType: Hashable { } // Merging objects with different wasm extensions is not allowed. - guard self.ext?.wasmExt == nil || other.ext?.wasmExt == nil || self.ext?.wasmExt == other.ext?.wasmExt else { + guard + self.ext?.wasmExt == nil || other.ext?.wasmExt == nil + || self.ext?.wasmExt == other.ext?.wasmExt + else { return false } @@ -888,15 +1002,18 @@ public struct ILType: Hashable { let wasmExt = self.wasmType ?? other.wasmType // We just take the self.wasmExt as they have to be the same, see `canMerge`. - let ext = TypeExtension(group: group, properties: self.properties.union(other.properties), methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, receiver: receiver) + let ext = TypeExtension( + group: group, properties: self.properties.union(other.properties), + methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, + receiver: receiver) return ILType(definiteType: definiteType, possibleType: possibleType, ext: ext) } - public static func +(lhs: ILType, rhs: ILType) -> ILType { + public static func + (lhs: ILType, rhs: ILType) -> ILType { return lhs.merging(with: rhs) } - public static func +=(lhs: inout ILType, rhs: ILType) { + public static func += (lhs: inout ILType, rhs: ILType) { lhs = lhs.merging(with: rhs) } @@ -913,7 +1030,9 @@ public struct ILType: Hashable { } var newProperties = properties newProperties.insert(property) - let newExt = TypeExtension(group: group, properties: newProperties, methods: methods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: newProperties, methods: methods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -933,7 +1052,9 @@ public struct ILType: Hashable { newProperties.remove(name) var newMethods = methods newMethods.remove(name) - let newExt = TypeExtension(group: group, properties: newProperties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: newProperties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -944,7 +1065,9 @@ public struct ILType: Hashable { } var newMethods = methods newMethods.insert(method) - let newExt = TypeExtension(group: group, properties: properties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: properties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -960,7 +1083,9 @@ public struct ILType: Hashable { } var newMethods = methods newMethods.remove(method) - let newExt = TypeExtension(group: group, properties: properties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: properties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -968,7 +1093,8 @@ public struct ILType: Hashable { guard Is(.function() | .constructor()) else { return self } - let newExt = TypeExtension(group: group, properties: properties, methods: methods, signature: signature) + let newExt = TypeExtension( + group: group, properties: properties, methods: methods, signature: signature) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1086,7 +1212,8 @@ extension ILType: CustomStringConvertible { return ".constructor()" } case .unboundFunction: - return ".unboundFunction(\(signature?.format(abbreviate: abbreviate) ?? "nil"), receiver: \(receiver?.format(abbreviate: abbreviate) ?? "nil"))" + return + ".unboundFunction(\(signature?.format(abbreviate: abbreviate) ?? "nil"), receiver: \(receiver?.format(abbreviate: abbreviate) ?? "nil"))" case .wasmi32: return ".wasmi32" case .wasmi64: @@ -1112,14 +1239,14 @@ extension ILType: CustomStringConvertible { } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapTypeInfo): - let sharedPrefix = heapTypeInfo.shared ? "shared " : "" - return ".wasmRef(.Abstract(\(nullPrefix)\(sharedPrefix)\(heapTypeInfo.heapType)))" - case .Index(let indexRef): - if let desc = indexRef.get() { - return ".wasmRef(\(nullPrefix)Index \(desc.format(abbreviate: abbreviate)))" - } - return ".wasmRef(\(nullPrefix)Index)" + case .Abstract(let heapTypeInfo): + let sharedPrefix = heapTypeInfo.shared ? "shared " : "" + return ".wasmRef(.Abstract(\(nullPrefix)\(sharedPrefix)\(heapTypeInfo.heapType)))" + case .Index(let indexRef): + if let desc = indexRef.get() { + return ".wasmRef(\(nullPrefix)Index \(desc.format(abbreviate: abbreviate)))" + } + return ".wasmRef(\(nullPrefix)Index)" } case .wasmFunctionDef: if let signature = wasmFunctionDefSignature { @@ -1171,35 +1298,35 @@ struct BaseType: OptionSet, Hashable { let rawValue: UInt32 // Base types - static let nothing = BaseType([]) - static let undefined = BaseType(rawValue: 1 << 0) - static let integer = BaseType(rawValue: 1 << 1) - static let bigint = BaseType(rawValue: 1 << 2) - static let float = BaseType(rawValue: 1 << 3) - static let boolean = BaseType(rawValue: 1 << 4) - static let string = BaseType(rawValue: 1 << 5) - static let regexp = BaseType(rawValue: 1 << 6) - static let object = BaseType(rawValue: 1 << 7) - static let function = BaseType(rawValue: 1 << 8) + static let nothing = BaseType([]) + static let undefined = BaseType(rawValue: 1 << 0) + static let integer = BaseType(rawValue: 1 << 1) + static let bigint = BaseType(rawValue: 1 << 2) + static let float = BaseType(rawValue: 1 << 3) + static let boolean = BaseType(rawValue: 1 << 4) + static let string = BaseType(rawValue: 1 << 5) + static let regexp = BaseType(rawValue: 1 << 6) + static let object = BaseType(rawValue: 1 << 7) + static let function = BaseType(rawValue: 1 << 8) static let constructor = BaseType(rawValue: 1 << 9) static let unboundFunction = BaseType(rawValue: 1 << 10) - static let iterable = BaseType(rawValue: 1 << 11) + static let iterable = BaseType(rawValue: 1 << 11) // Wasm Types - static let wasmi32 = BaseType(rawValue: 1 << 12) - static let wasmi64 = BaseType(rawValue: 1 << 13) - static let wasmf32 = BaseType(rawValue: 1 << 14) - static let wasmf64 = BaseType(rawValue: 1 << 15) + static let wasmi32 = BaseType(rawValue: 1 << 12) + static let wasmi64 = BaseType(rawValue: 1 << 13) + static let wasmf32 = BaseType(rawValue: 1 << 14) + static let wasmf64 = BaseType(rawValue: 1 << 15) // These are wasm internal types, these are never lifted as such and are only used to glue together dataflow in wasm. - static let label = BaseType(rawValue: 1 << 16) + static let label = BaseType(rawValue: 1 << 16) // Any catch block exposes such a label now to rethrow the exception caught by that catch. // Note that in wasm the label is actually the try block's label but as rethrows are only possible inside a catch // block, semantically having a label on the catch makes more sense. static let exceptionLabel = BaseType(rawValue: 1 << 17) // This is a reference to a table, which can be passed around to table instructions // The lifter will resolve this to the proper index when lifting. - static let wasmSimd128 = BaseType(rawValue: 1 << 18) + static let wasmSimd128 = BaseType(rawValue: 1 << 18) static let wasmFunctionDef = BaseType(rawValue: 1 << 19) // Wasm-gc types @@ -1215,11 +1342,21 @@ struct BaseType: OptionSet, Hashable { static let wasmDataSegment = BaseType(rawValue: 1 << 24) static let wasmElementSegment = BaseType(rawValue: 1 << 25) - static let jsAnything = BaseType([.undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable]) - - static let wasmAnything = BaseType([.wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef]) - - static let allBaseTypes: [BaseType] = [.undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable, .wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef] + static let jsAnything = BaseType([ + .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, + .unboundFunction, .bigint, .regexp, .iterable, + ]) + + static let wasmAnything = BaseType([ + .wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, + .wasmFunctionDef, + ]) + + static let allBaseTypes: [BaseType] = [ + .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, + .unboundFunction, .bigint, .regexp, .iterable, .wasmf32, .wasmi32, .wasmf64, .wasmi64, + .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef, + ] } class TypeExtension: Hashable { @@ -1241,8 +1378,13 @@ class TypeExtension: Hashable { // The receiver type of a function (used for unbound functions). let receiver: ILType? - init?(group: String? = nil, properties: Set, methods: Set, signature: Signature?, wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil) { - if group == nil && properties.isEmpty && methods.isEmpty && signature == nil && wasmExt == nil && receiver == nil { + init?( + group: String? = nil, properties: Set, methods: Set, signature: Signature?, + wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil + ) { + if group == nil && properties.isEmpty && methods.isEmpty && signature == nil + && wasmExt == nil && receiver == nil + { return nil } @@ -1254,7 +1396,7 @@ class TypeExtension: Hashable { self.receiver = receiver } - static func ==(lhs: TypeExtension, rhs: TypeExtension) -> Bool { + static func == (lhs: TypeExtension, rhs: TypeExtension) -> Bool { return lhs.properties == rhs.properties && lhs.methods == rhs.methods && lhs.group == rhs.group @@ -1276,7 +1418,7 @@ class TypeExtension: Hashable { // Base class that all Wasm types wih TypeExtension should inherit from. public class WasmTypeExtension: Hashable { - public static func ==(lhs: WasmTypeExtension, rhs: WasmTypeExtension) -> Bool { + public static func == (lhs: WasmTypeExtension, rhs: WasmTypeExtension) -> Bool { lhs.isEqual(to: rhs) } @@ -1392,7 +1534,7 @@ public class WasmLabelType: WasmTypeExtension { } public class WasmTypeDefinition: WasmTypeExtension { - var description : WasmTypeDescription? = nil + var description: WasmTypeDescription? = nil override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmTypeDefinition else { return false } @@ -1438,10 +1580,10 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { // runtime errors when trying to do so.) func isUsableInJS() -> Bool { switch self { - case .WasmExn, .WasmNoExn: - return false - default: - return true + case .WasmExn, .WasmNoExn: + return false + default: + return true } } @@ -1451,14 +1593,14 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { func getBottom() -> Self { switch self { - case .WasmExtern, .WasmNoExtern: - return .WasmNoExtern - case .WasmFunc, .WasmNoFunc: - return .WasmNoFunc - case .WasmAny, .WasmEq, .WasmI31, .WasmStruct, .WasmArray, .WasmNone: - return .WasmNone - case .WasmExn, .WasmNoExn: - return .WasmNoExn + case .WasmExtern, .WasmNoExtern: + return .WasmNoExtern + case .WasmFunc, .WasmNoFunc: + return .WasmNoFunc + case .WasmAny, .WasmEq, .WasmI31, .WasmStruct, .WasmArray, .WasmNone: + return .WasmNone + case .WasmExn, .WasmNoExn: + return .WasmNoExn } } @@ -1483,14 +1625,14 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { let a = min(self, other) let b = max(self, other) return switch a { - case .WasmAny: - .WasmAny - case .WasmEq, .WasmI31, .WasmStruct: - .WasmEq - case .WasmArray: - .WasmAny - case .WasmExtern, .WasmFunc, .WasmExn, .WasmNone, .WasmNoExtern, .WasmNoFunc, .WasmNoExn: - fatalError("unhandled subtyping for a=\(a) b=\(b)") + case .WasmAny: + .WasmAny + case .WasmEq, .WasmI31, .WasmStruct: + .WasmEq + case .WasmArray: + .WasmAny + case .WasmExtern, .WasmFunc, .WasmExn, .WasmNone, .WasmNoExtern, .WasmNoFunc, .WasmNoExn: + fatalError("unhandled subtyping for a=\(a) b=\(b)") } } @@ -1519,7 +1661,7 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { } } -public class HeapTypeInfo : Hashable { +public class HeapTypeInfo: Hashable { public let heapType: WasmAbstractHeapType public let shared: Bool @@ -1528,13 +1670,13 @@ public class HeapTypeInfo : Hashable { self.shared = shared } - public static func ==(lhs: HeapTypeInfo, rhs: HeapTypeInfo) -> Bool { + public static func == (lhs: HeapTypeInfo, rhs: HeapTypeInfo) -> Bool { return lhs.heapType == rhs.heapType && lhs.shared == rhs.shared } func union(_ other: HeapTypeInfo) -> HeapTypeInfo? { - if (shared != other.shared) { - return nil; + if shared != other.shared { + return nil } if let unionHeapType = heapType.union(other.heapType) { return HeapTypeInfo(unionHeapType, shared: shared) @@ -1543,8 +1685,8 @@ public class HeapTypeInfo : Hashable { } func intersection(_ other: HeapTypeInfo) -> HeapTypeInfo? { - if (shared != other.shared) { - return nil; + if shared != other.shared { + return nil } if let intersectionHeapType = heapType.intersection(other.heapType) { return HeapTypeInfo(intersectionHeapType, shared: shared) @@ -1553,13 +1695,12 @@ public class HeapTypeInfo : Hashable { } func subsumes(_ other: HeapTypeInfo) -> Bool { - if (shared != other.shared) { - return false; + if shared != other.shared { + return false } return heapType.subsumes(other.heapType) } - public func hash(into hasher: inout Hasher) { hasher.combine(heapType) hasher.combine(shared) @@ -1567,7 +1708,7 @@ public class HeapTypeInfo : Hashable { } // A wrapper around a WasmTypeDescription without owning the WasmTypeDescription. -struct UnownedWasmTypeDescription : Hashable { +struct UnownedWasmTypeDescription: Hashable { private unowned var description: WasmTypeDescription? init(_ description: WasmTypeDescription? = nil) { @@ -1580,7 +1721,7 @@ struct UnownedWasmTypeDescription : Hashable { } public class WasmReferenceType: WasmTypeExtension { - enum Kind : Hashable { + enum Kind: Hashable { // A user defined (indexed) wasm-gc type. Note that the WasmReferenceType may not own the // WasmTypeDescription as that would create cyclic references in case of self or forward // references (e.g. an array could have its own type as an element type) leading to memory @@ -1592,68 +1733,74 @@ public class WasmReferenceType: WasmTypeExtension { func union(_ other: Self) -> Self? { switch self { - case .Index(let desc): - switch other { - case .Index(let otherDesc): - if desc.get() == nil || otherDesc.get() == nil { - return .Index(.init()) - } - if desc.get() == otherDesc.get() { - return self - } - if let abstract = desc.get()?.abstractHeapSupertype, - let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - let upperBound = abstract.union(otherAbstract) { - return .Abstract(upperBound) - } - case .Abstract(let otherAbstract): - if let abstractSuper = desc.get()?.abstractHeapSupertype, - let upperBound = abstractSuper.union(otherAbstract) { - return .Abstract(upperBound) - } + case .Index(let desc): + switch other { + case .Index(let otherDesc): + if desc.get() == nil || otherDesc.get() == nil { + return .Index(.init()) } - case .Abstract(let heapType): - switch other { - case .Index(let otherDesc): - if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - let upperBound = heapType.union(otherAbstract) { - return .Abstract(upperBound) - } - case .Abstract(let otherHeapType): - if let upperBound = heapType.union(otherHeapType) { - return .Abstract(upperBound) - } + if desc.get() == otherDesc.get() { + return self } + if let abstract = desc.get()?.abstractHeapSupertype, + let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + let upperBound = abstract.union(otherAbstract) + { + return .Abstract(upperBound) + } + case .Abstract(let otherAbstract): + if let abstractSuper = desc.get()?.abstractHeapSupertype, + let upperBound = abstractSuper.union(otherAbstract) + { + return .Abstract(upperBound) + } + } + case .Abstract(let heapType): + switch other { + case .Index(let otherDesc): + if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + let upperBound = heapType.union(otherAbstract) + { + return .Abstract(upperBound) + } + case .Abstract(let otherHeapType): + if let upperBound = heapType.union(otherHeapType) { + return .Abstract(upperBound) + } + } } return nil } func intersection(_ other: Self) -> Self? { switch self { - case .Index(let desc): - switch other { - case .Index(let otherDesc): - if desc.get() == otherDesc.get() || desc.get() == nil || otherDesc.get() == nil { - return .Index(desc) - } - case .Abstract(let otherAbstract): - if let abstractSuper = desc.get()?.abstractHeapSupertype, - otherAbstract.subsumes(abstractSuper) { - return self - } + case .Index(let desc): + switch other { + case .Index(let otherDesc): + if desc.get() == otherDesc.get() || desc.get() == nil || otherDesc.get() == nil + { + return .Index(desc) } - case .Abstract(let heapType): - switch other { - case .Index(let otherDesc): - if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - heapType.subsumes(otherAbstract) { - return other - } - case .Abstract(let otherHeapType): - if let lowerBound = heapType.intersection(otherHeapType) { - return .Abstract(lowerBound) - } + case .Abstract(let otherAbstract): + if let abstractSuper = desc.get()?.abstractHeapSupertype, + otherAbstract.subsumes(abstractSuper) + { + return self } + } + case .Abstract(let heapType): + switch other { + case .Index(let otherDesc): + if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + heapType.subsumes(otherAbstract) + { + return other + } + case .Abstract(let otherHeapType): + if let lowerBound = heapType.intersection(otherHeapType) { + return .Abstract(lowerBound) + } + } } return nil } @@ -1668,10 +1815,10 @@ public class WasmReferenceType: WasmTypeExtension { func isAbstract() -> Bool { switch self.kind { - case .Abstract(_): - return true - case .Index(_): - return false + case .Abstract(_): + return true + case .Index(_): + return false } } @@ -1724,7 +1871,8 @@ public class WasmMemoryType: WasmTypeExtension { override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmMemoryType else { return false } - return self.limits == other.limits && self.isShared == other.isShared && self.isMemory64 == other.isMemory64 + return self.limits == other.limits && self.isShared == other.isShared + && self.isMemory64 == other.isMemory64 } override public func hash(into hasher: inout Hasher) { @@ -1808,7 +1956,8 @@ public class WasmTableType: WasmTypeExtension { override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmTableType else { return false } - return self.elementType == other.elementType && self.limits == other.limits && self.isTable64 == other.isTable64 && self.knownEntries == other.knownEntries + return self.elementType == other.elementType && self.limits == other.limits + && self.isTable64 == other.isTable64 && self.knownEntries == other.knownEntries } override public func hash(into hasher: inout Hasher) { @@ -1818,7 +1967,10 @@ public class WasmTableType: WasmTypeExtension { hasher.combine(knownEntries) } - init(elementType: ILType, limits: Limits, isTable64: Bool, knownEntries: [IndexInTableAndWasmSignature]) { + init( + elementType: ILType, limits: Limits, isTable64: Bool, + knownEntries: [IndexInTableAndWasmSignature] + ) { // TODO(manoskouk): Assert table type is reference type. self.elementType = elementType self.limits = limits @@ -1834,18 +1986,22 @@ public enum Parameter: Hashable { case rest(ILType) // Convenience constructors for plain parameters. - public static let integer = Parameter.plain(.integer) - public static let bigint = Parameter.plain(.bigint) - public static let float = Parameter.plain(.float) - public static let string = Parameter.plain(.string) - public static let boolean = Parameter.plain(.boolean) - public static let regexp = Parameter.plain(.regexp) - public static let iterable = Parameter.plain(.iterable) + public static let integer = Parameter.plain(.integer) + public static let bigint = Parameter.plain(.bigint) + public static let float = Parameter.plain(.float) + public static let string = Parameter.plain(.string) + public static let boolean = Parameter.plain(.boolean) + public static let regexp = Parameter.plain(.regexp) + public static let iterable = Parameter.plain(.iterable) public static let jsAnything = Parameter.plain(.jsAnything) - public static let number = Parameter.plain(.number) - public static let primitive = Parameter.plain(.primitive) - public static func object(ofGroup group: String? = nil, withProperties properties: [String] = [], withMethods methods: [String] = []) -> Parameter { - return Parameter.plain(.object(ofGroup: group, withProperties: properties, withMethods: methods)) + public static let number = Parameter.plain(.number) + public static let primitive = Parameter.plain(.primitive) + public static func object( + ofGroup group: String? = nil, withProperties properties: [String] = [], + withMethods methods: [String] = [] + ) -> Parameter { + return Parameter.plain( + .object(ofGroup: group, withProperties: properties, withMethods: methods)) } public static func function(_ signature: Signature? = nil) -> Parameter { return Parameter.plain(.function(signature)) @@ -1869,18 +2025,18 @@ public enum Parameter: Hashable { fileprivate func format(abbreviate: Bool) -> String { switch self { - case .plain(let t): - return t.format(abbreviate: abbreviate) - case .opt(let t): - return ".opt(\(t.format(abbreviate: abbreviate)))" - case .rest(let t): - return "\(t.format(abbreviate: abbreviate))..." + case .plain(let t): + return t.format(abbreviate: abbreviate) + case .opt(let t): + return ".opt(\(t.format(abbreviate: abbreviate)))" + case .rest(let t): + return "\(t.format(abbreviate: abbreviate))..." } } } // A ParameterList represents all parameters in a function signature. -public typealias ParameterList = Array +public typealias ParameterList = [Parameter] extension ParameterList { // Construct a generic parameter list with `numParameters` parameters of type `.jsAnything` init(numParameters: Int, hasRestParam: Bool) { @@ -1918,11 +2074,11 @@ extension ParameterList { /// Returns an array of `ILType`s. Requires the parameters to be plain parameters only. func convertPlainToILTypes() -> [ILType] { return map { param in - switch (param) { - case .plain(let plain): - return plain - default: - fatalError("Unexpected non-plain parameter \(param)") + switch param { + case .plain(let plain): + return plain + default: + fatalError("Unexpected non-plain parameter \(param)") } } } @@ -2085,11 +2241,11 @@ public struct Signature: Hashable, CustomStringConvertible { return true } - public static func >=(lhs: Signature, rhs: Signature) -> Bool { + public static func >= (lhs: Signature, rhs: Signature) -> Bool { return lhs.subsumes(rhs) } - public static func <=(lhs: Signature, rhs: Signature) -> Bool { + public static func <= (lhs: Signature, rhs: Signature) -> Bool { return rhs.subsumes(lhs) } } @@ -2109,7 +2265,8 @@ public struct WasmSignature: Hashable, CustomStringConvertible { } func format(abbreviate: Bool) -> String { - let inputs = parameterTypes.map({ $0.format(abbreviate: abbreviate) }).joined(separator: ", ") + let inputs = parameterTypes.map({ $0.format(abbreviate: abbreviate) }).joined( + separator: ", ") let outputs = outputTypes.map({ $0.format(abbreviate: abbreviate) }).joined(separator: ", ") return "[\(inputs)] => [\(outputs)]" } @@ -2127,7 +2284,7 @@ public postfix func ... (t: ILType) -> Parameter { } /// The convenience infix operator => is used to construct function signatures. -infix operator =>: AdditionPrecedence +infix operator => : AdditionPrecedence public func => (parameters: [Parameter], returnType: ILType) -> Signature { return Signature(expects: ParameterList(parameters), returns: returnType) } @@ -2176,7 +2333,8 @@ class WasmSignatureTypeDescription: WasmTypeDescription { init(signature: WasmSignature, typeGroupIndex: Int) { self.signature = signature // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2184,8 +2342,8 @@ class WasmSignatureTypeDescription: WasmTypeDescription { if abbreviate { return abbreviated } - let paramTypes = signature.parameterTypes.map {$0.abbreviated}.joined(separator: ", ") - let outputTypes = signature.outputTypes.map {$0.abbreviated}.joined(separator: ", ") + let paramTypes = signature.parameterTypes.map { $0.abbreviated }.joined(separator: ", ") + let outputTypes = signature.outputTypes.map { $0.abbreviated }.joined(separator: ", ") return "\(abbreviated)[[\(paramTypes)] => [\(outputTypes)]]" } } @@ -2198,7 +2356,8 @@ class WasmArrayTypeDescription: WasmTypeDescription { self.elementType = elementType self.mutability = mutability // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2230,7 +2389,9 @@ class WasmStructTypeDescription: WasmTypeDescription { init(fields: [Field], typeGroupIndex: Int) { self.fields = fields // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmStruct, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmStruct, shared: false) + ) } override func format(abbreviate: Bool) -> String { diff --git a/Sources/Fuzzilli/FuzzIL/Variable.swift b/Sources/Fuzzilli/FuzzIL/Variable.swift index 8c46fb94e..ca6882715 100644 --- a/Sources/Fuzzilli/FuzzIL/Variable.swift +++ b/Sources/Fuzzilli/FuzzIL/Variable.swift @@ -40,7 +40,7 @@ public struct Variable: Hashable, CustomStringConvertible { return "v\(number)" } - public static func ==(lhs: Variable, rhs: Variable) -> Bool { + public static func == (lhs: Variable, rhs: Variable) -> Bool { return lhs.number == rhs.number } @@ -50,7 +50,7 @@ public struct Variable: Hashable, CustomStringConvertible { } extension Variable: Comparable { - public static func <(lhs: Variable, rhs: Variable) -> Bool { + public static func < (lhs: Variable, rhs: Variable) -> Bool { return lhs.number < rhs.number } } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index cc9daa405..ef8e416b6 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. - import Foundation struct WasmConstants { - static let specWasmMemPageSize: Int = 65536 // 64 KB + static let specWasmMemPageSize: Int = 65536 // 64 KB // These are the limits defined in v8/src/wasm/wasm-limits.h which is based on https://www.w3.org/TR/wasm-js-api-2/#limits. // Note that the memory64 limits will be merged later on. // This constant limits the amount of *declared* memory. At runtime, memory can grow up to only a limit based on the architecture type. - static let specMaxWasmMem32Pages: Int = 65536 // 4GB - static let specMaxWasmMem64Pages: Int = 262144; // 16GB + static let specMaxWasmMem32Pages: Int = 65536 // 4GB + static let specMaxWasmMem64Pages: Int = 262144 // 16GB } // Base class for all wasm operations. -public class WasmOperation : Operation { +public class WasmOperation: Operation { } final class Consti64: WasmOperation { @@ -89,8 +88,8 @@ final class WasmReturn: WasmOperation { // public enum WasmIntegerCompareOpKind: UInt8, CaseIterable { - case Eq = 0 - case Ne = 1 + case Eq = 0 + case Ne = 1 case Lt_s = 2 case Lt_u = 3 case Gt_s = 4 @@ -124,7 +123,8 @@ final class Wasmi32CompareOp: WasmOperation { init(compareOpKind: WasmIntegerCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -134,7 +134,8 @@ final class Wasmi64CompareOp: WasmOperation { init(compareOpKind: WasmIntegerCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -170,7 +171,8 @@ final class Wasmf32CompareOp: WasmOperation { init(compareOpKind: WasmFloatCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -180,7 +182,8 @@ final class Wasmf64CompareOp: WasmOperation { init(compareOpKind: WasmFloatCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -238,7 +241,8 @@ final class Wasmi32BinOp: WasmOperation { init(binOpKind: WasmIntegerBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -248,7 +252,8 @@ final class Wasmi64BinOp: WasmOperation { init(binOpKind: WasmIntegerBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -304,18 +309,18 @@ public enum WasmAtomicRMWType: UInt8, CaseIterable { func type() -> ILType { switch self { case .i32Add, .i32Add8U, .i32Add16U, - .i32Sub, .i32Sub8U, .i32Sub16U, - .i32And, .i32And8U, .i32And16U, - .i32Or, .i32Or8U, .i32Or16U, - .i32Xor, .i32Xor8U, .i32Xor16U, - .i32Xchg, .i32Xchg8U, .i32Xchg16U: + .i32Sub, .i32Sub8U, .i32Sub16U, + .i32And, .i32And8U, .i32And16U, + .i32Or, .i32Or8U, .i32Or16U, + .i32Xor, .i32Xor8U, .i32Xor16U, + .i32Xchg, .i32Xchg8U, .i32Xchg16U: return .wasmi32 case .i64Add, .i64Add8U, .i64Add16U, .i64Add32U, - .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U, - .i64And, .i64And8U, .i64And16U, .i64And32U, - .i64Or, .i64Or8U, .i64Or16U, .i64Or32U, - .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U, - .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: + .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U, + .i64And, .i64And8U, .i64And16U, .i64And32U, + .i64Or, .i64Or8U, .i64Or16U, .i64Or32U, + .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U, + .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: return .wasmi64 } } @@ -323,29 +328,29 @@ public enum WasmAtomicRMWType: UInt8, CaseIterable { func naturalAlignment() -> Int64 { switch self { case .i32Add8U, .i64Add8U, - .i32Sub8U, .i64Sub8U, - .i32And8U, .i64And8U, - .i32Or8U, .i64Or8U, - .i32Xor8U, .i64Xor8U, - .i32Xchg8U, .i64Xchg8U: + .i32Sub8U, .i64Sub8U, + .i32And8U, .i64And8U, + .i32Or8U, .i64Or8U, + .i32Xor8U, .i64Xor8U, + .i32Xchg8U, .i64Xchg8U: return 1 case .i32Add16U, .i64Add16U, - .i32Sub16U, .i64Sub16U, - .i32And16U, .i64And16U, - .i32Or16U, .i64Or16U, - .i32Xor16U, .i64Xor16U, - .i32Xchg16U, .i64Xchg16U: + .i32Sub16U, .i64Sub16U, + .i32And16U, .i64And16U, + .i32Or16U, .i64Or16U, + .i32Xor16U, .i64Xor16U, + .i32Xchg16U, .i64Xchg16U: return 2 case .i32Add, .i64Add32U, - .i32Sub, .i64Sub32U, - .i32And, .i64And32U, - .i32Or, .i64Or32U, - .i32Xor, .i64Xor32U, - .i32Xchg, .i64Xchg32U: + .i32Sub, .i64Sub32U, + .i32And, .i64And32U, + .i32Or, .i64Or32U, + .i32Xor, .i64Xor32U, + .i32Xchg, .i64Xchg32U: return 4 case .i64Add, .i64Sub, - .i64And, .i64Or, - .i64Xor, .i64Xchg: + .i64And, .i64Or, + .i64Xor, .i64Xchg: return 8 } } @@ -357,7 +362,8 @@ final class Wasmi32UnOp: WasmOperation { init(unOpKind: WasmIntegerUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -367,7 +373,8 @@ final class Wasmi64UnOp: WasmOperation { init(unOpKind: WasmIntegerUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -405,7 +412,8 @@ final class Wasmf32BinOp: WasmOperation { init(binOpKind: WasmFloatBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -415,27 +423,30 @@ final class Wasmf64BinOp: WasmOperation { init(binOpKind: WasmFloatBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class Wasmf32UnOp: WasmOperation { - override var opcode: Opcode { .wasmf32UnOp(self)} + override var opcode: Opcode { .wasmf32UnOp(self) } let unOpKind: WasmFloatUnaryOpKind init(unOpKind: WasmFloatUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class Wasmf64UnOp: WasmOperation { - override var opcode: Opcode { .wasmf64UnOp(self)} + override var opcode: Opcode { .wasmf64UnOp(self) } let unOpKind: WasmFloatUnaryOpKind init(unOpKind: WasmFloatUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -703,7 +714,6 @@ public enum WasmGlobal { // This is the case for imported Globals, we just need the type here. case imported(ILType) - func toType() -> ILType { switch self { case .wasmi64: @@ -728,7 +738,7 @@ public enum WasmGlobal { } } -func typeString() -> String { + func typeString() -> String { switch self { case .wasmi64(_): return "i64" @@ -749,9 +759,8 @@ func typeString() -> String { } } - // Returns a JS string representing the initial value. -func valueToString() -> String { + func valueToString() -> String { switch self { case .wasmi64(let val): return "\(val)n" @@ -764,7 +773,7 @@ func valueToString() -> String { case .externref: return "" case .exnref, - .i31ref: + .i31ref: return "null" default: fatalError("Unimplemented / unhandled") @@ -794,7 +803,10 @@ final class WasmDefineTable: WasmOperation { let definedEntries: [WasmTableType.IndexInTableAndWasmSignature] let isTable64: Bool - init(elementType: ILType, limits: Limits, definedEntries: [WasmTableType.IndexInTableAndWasmSignature], isTable64: Bool) { + init( + elementType: ILType, limits: Limits, + definedEntries: [WasmTableType.IndexInTableAndWasmSignature], isTable64: Bool + ) { self.elementType = elementType self.limits = limits self.isTable64 = isTable64 @@ -804,10 +816,11 @@ final class WasmDefineTable: WasmOperation { let isWasmFuncRef = elementType == .wasmFuncRef() assert(isWasmFuncRef || definedEntries.isEmpty) - super.init(numInputs: isWasmFuncRef ? definedEntries.count : 0, - numOutputs: 1, - attributes: [.isMutable], - requiredContext: [.wasm]) + super.init( + numInputs: isWasmFuncRef ? definedEntries.count : 0, + numOutputs: 1, + attributes: [.isMutable], + requiredContext: [.wasm]) } } @@ -892,7 +905,9 @@ final class WasmLoadGlobal: WasmOperation { init(globalType: ILType) { assert(globalType.Is(.wasmPrimitive)) self.globalType = globalType - super.init(numInputs: 1, numOutputs: 1, attributes: [.isNotInputMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isNotInputMutable], + requiredContext: [.wasmFunction]) } } @@ -947,7 +962,9 @@ final class WasmCallIndirect: WasmOperation { init(signature: WasmSignature) { self.signature = signature - super.init(numInputs: 2 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, + requiredContext: [.wasmFunction]) } } @@ -955,20 +972,24 @@ final class WasmCallDirect: WasmOperation { override var opcode: Opcode { .wasmCallDirect(self) } init(parameterCount: Int, outputCount: Int) { - super.init(numInputs: 1 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallDirect: WasmOperation { override var opcode: Opcode { .wasmReturnCallDirect(self) } init(parameterCount: Int) { - super.init(numInputs: 1 + parameterCount, numOutputs: 0, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numOutputs: 0, attributes: [.isJump], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallIndirect: WasmOperation { @@ -977,7 +998,9 @@ final class WasmReturnCallIndirect: WasmOperation { init(signature: WasmSignature) { self.signature = signature - super.init(numInputs: 2 + signature.parameterTypes.count, numOutputs: 0, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + signature.parameterTypes.count, numOutputs: 0, attributes: [.isJump], + requiredContext: [.wasmFunction]) } } @@ -1012,24 +1035,24 @@ public enum WasmMemoryLoadType: UInt8, CaseIterable { func numberType() -> ILType { switch self { - case .I32LoadMem, - .I32LoadMem8S, - .I32LoadMem8U, - .I32LoadMem16S, - .I32LoadMem16U: - return .wasmi32 - case .I64LoadMem, - .I64LoadMem8S, - .I64LoadMem8U, - .I64LoadMem16S, - .I64LoadMem16U, - .I64LoadMem32S, - .I64LoadMem32U: - return .wasmi64 - case .F32LoadMem: - return .wasmf32 - case .F64LoadMem: - return .wasmf64 + case .I32LoadMem, + .I32LoadMem8S, + .I32LoadMem8U, + .I32LoadMem16S, + .I32LoadMem16U: + return .wasmi32 + case .I64LoadMem, + .I64LoadMem8S, + .I64LoadMem8U, + .I64LoadMem16S, + .I64LoadMem16U, + .I64LoadMem32S, + .I64LoadMem32U: + return .wasmi64 + case .F32LoadMem: + return .wasmf32 + case .F64LoadMem: + return .wasmf64 } } } @@ -1043,7 +1066,8 @@ final class WasmMemoryLoad: WasmOperation { init(loadType: WasmMemoryLoadType, staticOffset: Int64) { self.loadType = loadType self.staticOffset = staticOffset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1058,25 +1082,25 @@ public enum WasmMemoryStoreType: UInt8, CaseIterable { case I64StoreMem8 = 0x3c case I64StoreMem16 = 0x3d case I64StoreMem32 = 0x3e - case S128StoreMem = 0x0B // Requires SIMD prefix! + case S128StoreMem = 0x0B // Requires SIMD prefix! func numberType() -> ILType { switch self { - case .I32StoreMem, - .I32StoreMem8, - .I32StoreMem16: - return .wasmi32 - case .I64StoreMem, - .I64StoreMem8, - .I64StoreMem16, - .I64StoreMem32: - return .wasmi64 - case .F32StoreMem: - return .wasmf32 - case .F64StoreMem: - return .wasmf64 - case .S128StoreMem: - return .wasmSimd128 + case .I32StoreMem, + .I32StoreMem8, + .I32StoreMem16: + return .wasmi32 + case .I64StoreMem, + .I64StoreMem8, + .I64StoreMem16, + .I64StoreMem32: + return .wasmi64 + case .F32StoreMem: + return .wasmf32 + case .F64StoreMem: + return .wasmf64 + case .S128StoreMem: + return .wasmSimd128 } } } @@ -1217,7 +1241,9 @@ final class WasmJsCall: WasmOperation { override var opcode: Opcode { .wasmJsCall(self) } init(parameterCount: Int, outputCount: Int) { - super.init(numInputs: 2 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } var parameterCount: Int { numInputs - 2 } @@ -1241,21 +1267,26 @@ final class WasmBeginBlock: WasmOperation { init(parameterCount: Int) { // Inputs: The signature plus the arguments. // Inner outputs: The label plus the arguments. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmEndBlock: WasmOperation { override var opcode: Opcode { .wasmEndBlock(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } -public enum WasmBranchHint: CaseIterable { +public enum WasmBranchHint: CaseIterable { case None case Likely case Unlikely @@ -1274,10 +1305,13 @@ final class WasmBeginIf: WasmOperation { // it needs to be the last one pushed to it. // Inputs: The signature, the arguments and the condition. // Inner outputs: 1 label (used for branch instructions) plus all the parameters. - super.init(numInputs: 2 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext, .isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext, .isMutable], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 2} + var parameterCount: Int { numInputs - 2 } } final class WasmBeginElse: WasmOperation { @@ -1288,21 +1322,26 @@ final class WasmBeginElse: WasmOperation { // The WasmBeginElse acts both as a block end for the true case and as a block start for the // false case. As such, its input types are the results from the true block and its inner // output types are the same as for the corresponding WasmBeginIf. - super.init(numInputs: 1 + outputCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInnerOutputs - 1} - var outputCount: Int {numInputs - 1} + var parameterCount: Int { numInnerOutputs - 1 } + var outputCount: Int { numInputs - 1 } } final class WasmEndIf: WasmOperation { override var opcode: Opcode { .wasmEndIf(self) } init(outputCount: Int = 0) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd], + requiredContext: [.wasmFunction]) } - var outputCount: Int {numInputs - 1} + var outputCount: Int { numInputs - 1 } } final class WasmBeginLoop: WasmOperation { @@ -1311,14 +1350,17 @@ final class WasmBeginLoop: WasmOperation { init(parameterCount: Int) { // Inputs: the signature + the inputs to the loop. // inner outputs: The loop label + the arguments of the loop. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } convenience init(with signature: WasmSignature) { self.init(parameterCount: signature.parameterTypes.count) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmEndLoop: WasmOperation { @@ -1326,14 +1368,16 @@ final class WasmEndLoop: WasmOperation { init(outputCount: Int) { // Inputs: the signature + the outputs of the loop. - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } // A try_table is a mix between a `br_table` (just with target blocks associated with different tags) // and the legacy `try` block. final class WasmBeginTryTable: WasmOperation { - enum CatchKind : UInt8 { + enum CatchKind: UInt8 { case NoRef = 0x0 case Ref = 0x1 case AllNoRef = 0x2 @@ -1345,22 +1389,24 @@ final class WasmBeginTryTable: WasmOperation { init(parameterCount: Int, catches: [CatchKind]) { self.catches = catches - let inputTagCount = catches.count {$0 == .Ref || $0 == .NoRef} + let inputTagCount = catches.count { $0 == .Ref || $0 == .NoRef } let inputLabelCount = catches.count - super.init(numInputs: 1 + parameterCount + inputLabelCount + inputTagCount, + super.init( + numInputs: 1 + parameterCount + inputLabelCount + inputTagCount, numInnerOutputs: parameterCount + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInnerOutputs - 1} + var parameterCount: Int { numInnerOutputs - 1 } } final class WasmEndTryTable: WasmOperation { override var opcode: Opcode { .wasmEndTryTable(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } @@ -1371,33 +1417,34 @@ final class WasmBeginTry: WasmOperation { init(parameterCount: Int) { // Inputs: The block signature and the block arguments. // Inner outputs: The label and the block parameters. - super.init(numInputs: 1 + parameterCount, + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } } -final class WasmBeginCatchAll : WasmOperation { +final class WasmBeginCatchAll: WasmOperation { override var opcode: Opcode { .wasmBeginCatchAll(self) } init(blockOutputCount: Int) { // Inputs: The block signature and the outputs of the preceding try or catch block. super.init( numInputs: 1 + blockOutputCount, - numInnerOutputs: 1, // the label + numInnerOutputs: 1, // the label attributes: [ .isBlockEnd, .isBlockStart, .propagatesSurroundingContext, // Wasm only allows a single catch_all per try block. - .isSingular + .isSingular, ], requiredContext: [.wasmFunction]) } } -final class WasmBeginCatch : WasmOperation { +final class WasmBeginCatch: WasmOperation { override var opcode: Opcode { .wasmBeginCatch(self) } init(blockOutputCount: Int, labelParameterCount: Int) { @@ -1421,15 +1468,16 @@ final class WasmBeginCatch : WasmOperation { requiredContext: [.wasmFunction]) } - var blockOutputCount: Int {numInputs - 3} - var labelParameterCount: Int {numInnerOutputs - 2} + var blockOutputCount: Int { numInputs - 3 } + var labelParameterCount: Int { numInnerOutputs - 2 } } final class WasmEndTry: WasmOperation { override var opcode: Opcode { .wasmEndTry(self) } init(blockOutputCount: Int) { - super.init(numInputs: 1 + blockOutputCount, numOutputs: blockOutputCount, + super.init( + numInputs: 1 + blockOutputCount, numOutputs: blockOutputCount, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) } } @@ -1441,7 +1489,8 @@ final class WasmBeginTryDelegate: WasmOperation { init(parameterCount: Int) { // inputs: The signature and the arguments. // innerOutputs: The label and the arguments. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } @@ -1455,7 +1504,8 @@ final class WasmEndTryDelegate: WasmOperation { init(outputCount: Int) { // Inputs: The signature, the label to delegate an exception to plus all the outputs of the // try block. - super.init(numInputs: 2 + outputCount, numOutputs: outputCount, + super.init( + numInputs: 2 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } @@ -1465,7 +1515,8 @@ final class WasmThrow: WasmOperation { init(parameterCount: Int) { // Inputs: the tag to be thrown plus the arguments for each parameter type of the tag. - super.init(numInputs: 1 + parameterCount, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, attributes: [.isJump], requiredContext: [.wasmFunction]) } } @@ -1494,7 +1545,7 @@ final class WasmBranch: WasmOperation { super.init(numInputs: 1 + parameterCount, requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmBranchIf: WasmOperation { @@ -1504,10 +1555,12 @@ final class WasmBranchIf: WasmOperation { init(parameterCount: Int, hint: WasmBranchHint) { self.hint = hint // The inputs are the label, the arguments and the condition. - super.init(numInputs: 1 + parameterCount + 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount + 1, attributes: [.isMutable], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 2} + var parameterCount: Int { numInputs - 2 } } final class WasmBranchTable: WasmOperation { @@ -1522,7 +1575,7 @@ final class WasmBranchTable: WasmOperation { super.init(numInputs: valueCount + 1 + parameterCount + 1, requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - valueCount - 2} + var parameterCount: Int { numInputs - valueCount - 2 } } // TODO: make this comprehensive, currently only works for locals, or assumes every thing it reassigns to is a local. @@ -1545,7 +1598,9 @@ final class BeginWasmFunction: WasmOperation { override var opcode: Opcode { .beginWasmFunction(self) } init(parameterCount: Int) { - super.init(numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) + super.init( + numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], + requiredContext: [.wasm], contextOpened: [.wasmFunction]) } var parameterCount: Int { numInnerOutputs - 1 } @@ -1555,7 +1610,9 @@ final class EndWasmFunction: WasmOperation { override var opcode: Opcode { .endWasmFunction(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], + requiredContext: [.wasmFunction]) } var outputCount: Int { numInputs - 1 } @@ -1570,7 +1627,9 @@ final class WasmNop: WasmOperation { init(outputType: ILType, innerOutputTypes: [ILType]) { self.outputType = outputType self.innerOutputTypes = innerOutputTypes - super.init(numOutputs: outputType != .nothing ? 1 : 0, numInnerOutputs: innerOutputTypes.count, attributes: [.isInternal, .isNop], requiredContext: [.wasmFunction]) + super.init( + numOutputs: outputType != .nothing ? 1 : 0, numInnerOutputs: innerOutputTypes.count, + attributes: [.isInternal, .isNop], requiredContext: [.wasmFunction]) } } @@ -1586,7 +1645,7 @@ final class ConstSimd128: WasmOperation { let value: [UInt8] init(value: [UInt8]) { - self.value = value; + self.value = value super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1618,23 +1677,23 @@ extension WasmSimd128CompareOpKind: CustomStringConvertible { } public enum WasmSimd128Shape: UInt8, CaseIterable { - case i8x16 = 0 - case i16x8 = 1 - case i32x4 = 2 - case i64x2 = 3 - case f32x4 = 4 - case f64x2 = 5 + case i8x16 = 0 + case i16x8 = 1 + case i32x4 = 2 + case i64x2 = 3 + case f32x4 = 4 + case f64x2 = 5 func isFloat() -> Bool { switch self { - case .i8x16, - .i16x8, - .i32x4, - .i64x2: - return false - case .f32x4, - .f64x2: - return true + case .i8x16, + .i16x8, + .i32x4, + .i64x2: + return false + case .f32x4, + .f64x2: + return true } } } @@ -1647,7 +1706,8 @@ final class WasmSimd128Compare: WasmOperation { init(shape: WasmSimd128Shape, compareOpKind: WasmSimd128CompareOpKind) { self.shape = shape self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1661,40 +1721,40 @@ public enum WasmSimd128IntegerUnOpKind: Int, CaseIterable { case extadd_pairwise_i8x16_u = 1 case extadd_pairwise_i16x8_s = -30 case extadd_pairwise_i16x8_u = -29 - case abs = 4 - case neg = 5 - case popcnt = 6 - case all_true = 7 - case bitmask = 8 - case extend_low_s = 11 - case extend_high_s = 12 - case extend_low_u = 13 - case extend_high_u = 14 - - case relaxed_trunc_f32x4_s = 101 - case relaxed_trunc_f32x4_u = 102 + case abs = 4 + case neg = 5 + case popcnt = 6 + case all_true = 7 + case bitmask = 8 + case extend_low_s = 11 + case extend_high_s = 12 + case extend_low_u = 13 + case extend_high_u = 14 + + case relaxed_trunc_f32x4_s = 101 + case relaxed_trunc_f32x4_u = 102 case relaxed_trunc_f64x2_s_zero = 103 case relaxed_trunc_f64x2_u_zero = 104 func isValidForShape(shape: WasmSimd128Shape) -> Bool { if shape.isFloat() { return false } switch self { - case .extadd_pairwise_i8x16_s: return shape == .i16x8 - case .extadd_pairwise_i8x16_u: return shape == .i16x8 - case .extadd_pairwise_i16x8_s: return shape == .i32x4 - case .extadd_pairwise_i16x8_u: return shape == .i32x4 - case .abs: return true - case .neg: return true - case .popcnt: return shape == .i8x16 - case .all_true: return true - case .bitmask: return true - case .extend_low_s: return shape != .i8x16 - case .extend_high_s: return shape != .i8x16 - case .extend_low_u: return shape != .i8x16 - case .extend_high_u: return shape != .i8x16 - - case .relaxed_trunc_f32x4_s: return shape == .i32x4 - case .relaxed_trunc_f32x4_u: return shape == .i32x4 + case .extadd_pairwise_i8x16_s: return shape == .i16x8 + case .extadd_pairwise_i8x16_u: return shape == .i16x8 + case .extadd_pairwise_i16x8_s: return shape == .i32x4 + case .extadd_pairwise_i16x8_u: return shape == .i32x4 + case .abs: return true + case .neg: return true + case .popcnt: return shape == .i8x16 + case .all_true: return true + case .bitmask: return true + case .extend_low_s: return shape != .i8x16 + case .extend_high_s: return shape != .i8x16 + case .extend_low_u: return shape != .i8x16 + case .extend_high_u: return shape != .i8x16 + + case .relaxed_trunc_f32x4_s: return shape == .i32x4 + case .relaxed_trunc_f32x4_u: return shape == .i32x4 case .relaxed_trunc_f64x2_s_zero: return shape == .i32x4 case .relaxed_trunc_f64x2_u_zero: return shape == .i32x4 } @@ -1710,7 +1770,8 @@ final class WasmSimd128IntegerUnOp: WasmOperation { assert(unOpKind.isValidForShape(shape: shape)) self.shape = shape self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1721,42 +1782,42 @@ public enum WasmSimd128IntegerBinOpKind: Int, CaseIterable { // i32x4: 0x9C + offset // i64x2: 0xBC + offset case q15mulr_sat_s = 6 - case narrow_s = 9 - case narrow_u = 10 - - case shl = 15 - case shr_s = 16 - case shr_u = 17 - case add = 18 - case add_sat_s = 19 - case add_sat_u = 20 - case sub = 21 - case sub_sat_s = 22 - case sub_sat_u = 23 - - case mul = 25 - case min_s = 26 - case min_u = 27 - case max_s = 28 - case max_u = 29 - case dot_i16x8_s = 30 - case avgr_u = 31 - case extmul_low_s = 32 + case narrow_s = 9 + case narrow_u = 10 + + case shl = 15 + case shr_s = 16 + case shr_u = 17 + case add = 18 + case add_sat_s = 19 + case add_sat_u = 20 + case sub = 21 + case sub_sat_s = 22 + case sub_sat_u = 23 + + case mul = 25 + case min_s = 26 + case min_u = 27 + case max_s = 28 + case max_u = 29 + case dot_i16x8_s = 30 + case avgr_u = 31 + case extmul_low_s = 32 case extmul_high_s = 33 - case extmul_low_u = 34 + case extmul_low_u = 34 case extmul_high_u = 35 - case relaxed_q15_mulr_s = 149 - case relaxed_dot_i8x16_i7x16_s = 150 + case relaxed_q15_mulr_s = 149 + case relaxed_dot_i8x16_i7x16_s = 150 - case relaxed_swizzle = 164 + case relaxed_swizzle = 164 func isShift() -> Bool { switch self { - case .shl, .shr_s, .shr_u: - return true - default: - return false + case .shl, .shr_s, .shr_u: + return true + default: + return false } } @@ -1764,32 +1825,32 @@ public enum WasmSimd128IntegerBinOpKind: Int, CaseIterable { if shape.isFloat() { return false } switch self { case .q15mulr_sat_s: return shape == .i16x8 - case .narrow_s: return shape == .i8x16 || shape == .i16x8 - case .narrow_u: return shape == .i8x16 || shape == .i16x8 - case .shl: return true - case .shr_s: return true - case .shr_u: return true - case .add: return true - case .add_sat_s: return shape == .i8x16 || shape == .i16x8 - case .add_sat_u: return shape == .i8x16 || shape == .i16x8 - case .sub: return true - case .sub_sat_s: return shape == .i8x16 || shape == .i16x8 - case .sub_sat_u: return shape == .i8x16 || shape == .i16x8 - case .mul: return shape != .i8x16 - case .min_s: return shape != .i64x2 - case .min_u: return shape != .i64x2 - case .max_s: return shape != .i64x2 - case .max_u: return shape != .i64x2 - case .dot_i16x8_s: return shape == .i32x4 - case .avgr_u: return shape == .i8x16 || shape == .i16x8 - case .extmul_low_s: return shape != .i8x16 + case .narrow_s: return shape == .i8x16 || shape == .i16x8 + case .narrow_u: return shape == .i8x16 || shape == .i16x8 + case .shl: return true + case .shr_s: return true + case .shr_u: return true + case .add: return true + case .add_sat_s: return shape == .i8x16 || shape == .i16x8 + case .add_sat_u: return shape == .i8x16 || shape == .i16x8 + case .sub: return true + case .sub_sat_s: return shape == .i8x16 || shape == .i16x8 + case .sub_sat_u: return shape == .i8x16 || shape == .i16x8 + case .mul: return shape != .i8x16 + case .min_s: return shape != .i64x2 + case .min_u: return shape != .i64x2 + case .max_s: return shape != .i64x2 + case .max_u: return shape != .i64x2 + case .dot_i16x8_s: return shape == .i32x4 + case .avgr_u: return shape == .i8x16 || shape == .i16x8 + case .extmul_low_s: return shape != .i8x16 case .extmul_high_s: return shape != .i8x16 - case .extmul_low_u: return shape != .i8x16 + case .extmul_low_u: return shape != .i8x16 case .extmul_high_u: return shape != .i8x16 - case .relaxed_q15_mulr_s: return shape == .i16x8 - case .relaxed_dot_i8x16_i7x16_s: return shape == .i16x8 - case .relaxed_swizzle: return shape == .i8x16 + case .relaxed_q15_mulr_s: return shape == .i16x8 + case .relaxed_dot_i8x16_i7x16_s: return shape == .i16x8 + case .relaxed_swizzle: return shape == .i8x16 } } } @@ -1803,7 +1864,8 @@ final class WasmSimd128IntegerBinOp: WasmOperation { assert(binOpKind.isValidForShape(shape: shape)) self.shape = shape self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1819,8 +1881,8 @@ public enum WasmSimd128IntegerTernaryOpKind: Int, CaseIterable { func isValidForShape(shape: WasmSimd128Shape) -> Bool { if shape.isFloat() { return false } switch self { - case .relaxed_laneselect: return true - case .relaxed_dot_i8x16_i7x16_add_s: return shape == .i32x4 + case .relaxed_laneselect: return true + case .relaxed_dot_i8x16_i7x16_add_s: return shape == .i32x4 } } } @@ -1834,7 +1896,8 @@ final class WasmSimd128IntegerTernaryOp: WasmOperation { assert(ternaryOpKind.isValidForShape(shape: shape)) self.shape = shape self.ternaryOpKind = ternaryOpKind - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1861,7 +1924,8 @@ final class WasmSimd128FloatUnOp: WasmOperation { assert(unOpKind.isValidForShape(shape: shape)) self.shape = shape self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1901,15 +1965,17 @@ final class WasmSimd128FloatBinOp: WasmOperation { assert(binOpKind.isValidForShape(shape: shape)) self.shape = shape self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } func getOpcode() -> Int { - let base = if(binOpKind.isRelaxed()) { - shape == .f32x4 ? 0x100 : 0x102; - } else { - shape == .f32x4 ? 0xE4 : 0xF0; - } + let base = + if binOpKind.isRelaxed() { + shape == .f32x4 ? 0x100 : 0x102 + } else { + shape == .f32x4 ? 0xE4 : 0xF0 + } return base + binOpKind.rawValue } } @@ -1934,7 +2000,8 @@ final class WasmSimd128FloatTernaryOp: WasmOperation { assert(ternaryOpKind.isValidForShape(shape: shape)) self.shape = shape self.ternaryOpKind = ternaryOpKind - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1949,14 +2016,14 @@ final class WasmSimdSplat: WasmOperation { func laneType() -> ILType { switch self { - case .I8x16, .I16x8, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16, .I16x8, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } } @@ -1983,27 +2050,27 @@ final class WasmSimdExtractLane: WasmOperation { func laneType() -> ILType { switch self { - case .I8x16S, .I8x16U, .I16x8S, .I16x8U, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16S, .I8x16U, .I16x8S, .I16x8U, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } func laneCount() -> Int { switch self { - case .I8x16S, .I8x16U: - return 16 - case .I16x8S, .I16x8U: - return 8 - case .I32x4, .F32x4: - return 4 - case .I64x2, .F64x2: - return 2 + case .I8x16S, .I8x16U: + return 16 + case .I16x8S, .I16x8U: + return 8 + case .I32x4, .F32x4: + return 4 + case .I64x2, .F64x2: + return 2 } } } @@ -2014,8 +2081,9 @@ final class WasmSimdExtractLane: WasmOperation { init(kind: Kind, lane: Int) { self.kind = kind - self.lane = lane; - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2030,27 +2098,27 @@ final class WasmSimdReplaceLane: WasmOperation { func laneCount() -> Int { switch self { - case .I8x16: - return 16 - case .I16x8: - return 8 - case .I32x4, .F32x4: - return 4 - case .I64x2, .F64x2: - return 2 + case .I8x16: + return 16 + case .I16x8: + return 8 + case .I32x4, .F32x4: + return 4 + case .I64x2, .F64x2: + return 2 } } func laneType() -> ILType { switch self { - case .I8x16, .I16x8, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16, .I16x8, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } } @@ -2061,12 +2129,12 @@ final class WasmSimdReplaceLane: WasmOperation { init(kind: Kind, lane: Int) { self.kind = kind - self.lane = lane; - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } - final class WasmSimdStoreLane: WasmOperation { enum Kind: UInt8, CaseIterable { case Store8 = 0x58 @@ -2076,14 +2144,14 @@ final class WasmSimdStoreLane: WasmOperation { func laneCount() -> Int { switch self { - case .Store8: - return 16 - case .Store16: - return 8 - case .Store32: - return 4 - case .Store64: - return 2 + case .Store8: + return 16 + case .Store16: + return 8 + case .Store32: + return 4 + case .Store64: + return 2 } } } @@ -2096,7 +2164,7 @@ final class WasmSimdStoreLane: WasmOperation { init(kind: Kind, staticOffset: Int64, lane: Int) { self.kind = kind self.staticOffset = staticOffset - self.lane = lane; + self.lane = lane super.init(numInputs: 3, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2110,14 +2178,14 @@ final class WasmSimdLoadLane: WasmOperation { func laneCount() -> Int { switch self { - case .Load8: - return 16 - case .Load16: - return 8 - case .Load32: - return 4 - case .Load64: - return 2 + case .Load8: + return 16 + case .Load16: + return 8 + case .Load32: + return 4 + case .Load64: + return 2 } } } @@ -2130,26 +2198,27 @@ final class WasmSimdLoadLane: WasmOperation { init(kind: Kind, staticOffset: Int64, lane: Int) { self.kind = kind self.staticOffset = staticOffset - self.lane = lane; - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class WasmSimdLoad: WasmOperation { enum Kind: UInt8, CaseIterable { - case LoadS128 = 0x00 - case Load8x8S = 0x01 - case Load8x8U = 0x02 - case Load16x4S = 0x03 - case Load16x4U = 0x04 - case Load32x2S = 0x05 - case Load32x2U = 0x06 - case Load8Splat = 0x07 + case LoadS128 = 0x00 + case Load8x8S = 0x01 + case Load8x8U = 0x02 + case Load16x4S = 0x03 + case Load16x4U = 0x04 + case Load32x2S = 0x05 + case Load32x2U = 0x06 + case Load8Splat = 0x07 case Load16Splat = 0x08 case Load32Splat = 0x09 case Load64Splat = 0x0A - case Load32Zero = 0x5C - case Load64Zero = 0x5D + case Load32Zero = 0x5C + case Load64Zero = 0x5D } override var opcode: Opcode { .wasmSimdLoad(self) } @@ -2160,7 +2229,8 @@ final class WasmSimdLoad: WasmOperation { init(kind: Kind, staticOffset: Int64) { self.kind = kind self.staticOffset = staticOffset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2323,7 +2393,9 @@ class WasmRefTest: WasmOperation { init(refType: ILType) { self.type = refType - super.init(numInputs: 1 + type.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) } } @@ -2332,7 +2404,9 @@ class WasmRefCast: WasmOperation { let type: ILType init(refType: ILType) { self.type = refType - super.init(numInputs: 1 + type.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) } } @@ -2349,7 +2423,8 @@ final class WasmAtomicLoad: WasmOperation { init(loadType: WasmAtomicLoadType, offset: Int64) { self.loadType = loadType self.offset = offset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2366,7 +2441,8 @@ final class WasmAtomicStore: WasmOperation { init(storeType: WasmAtomicStoreType, offset: Int64) { self.storeType = storeType self.offset = offset - super.init(numInputs: 3, numOutputs: 0, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 0, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2379,7 +2455,8 @@ final class WasmAtomicRMW: WasmOperation { init(op: WasmAtomicRMWType, offset: Int64) { self.op = op self.offset = offset - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2424,7 +2501,8 @@ final class WasmAtomicCmpxchg: WasmOperation { init(op: WasmAtomicCmpxchgType, offset: Int64) { self.op = op self.offset = offset - super.init(numInputs: 4, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 4, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2435,7 +2513,8 @@ final class WasmDefineAdHocSignatureType: WasmOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasmFunction]) } } @@ -2452,7 +2531,8 @@ final class WasmDefineAdHocModuleSignatureType: WasmOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasm]) } } diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 787db836c..09b1ce265 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -21,12 +21,12 @@ public enum Timeout { case value(UInt32) case interval(UInt32, UInt32) - public func maxTimeout() -> UInt32{ + public func maxTimeout() -> UInt32 { switch self { - case .value(let value): - return value - case .interval(_, let max): - return max + case .value(let value): + return value + case .interval(_, let max): + return max } } } @@ -119,9 +119,9 @@ public class Fuzzer { logger.info("Changing state from \(state) to \(newState)") // Some state transitions are forbidden, check for those here. - assert(newState != .uninitialized) // We never transition into .uninitialized - assert(newState != .waiting || state == .uninitialized) // We're only transitioning into .waiting during initialization - assert(state != .fuzzing) // Currently we never transition out of .fuzzing (although we could allow scheduling a corpus import while already fuzzing) + assert(newState != .uninitialized) // We never transition into .uninitialized + assert(newState != .waiting || state == .uninitialized) // We're only transitioning into .waiting during initialization + assert(state != .fuzzing) // Currently we never transition out of .fuzzing (although we could allow scheduling a corpus import while already fuzzing) state = newState } @@ -182,13 +182,17 @@ public class Fuzzer { /// Constructs a new fuzzer instance with the provided components. public init( - configuration: Configuration, scriptRunner: ScriptRunner, referenceScriptRunner: ScriptRunner?, engine: FuzzEngine, mutators: WeightedList, - codeGenerators: WeightedList, programTemplates: WeightedList, evaluator: ProgramEvaluator, - environment: JavaScriptEnvironment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, queue: DispatchQueue? = nil + configuration: Configuration, scriptRunner: ScriptRunner, + referenceScriptRunner: ScriptRunner?, engine: FuzzEngine, mutators: WeightedList, + codeGenerators: WeightedList, + programTemplates: WeightedList, evaluator: ProgramEvaluator, + environment: JavaScriptEnvironment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, + queue: DispatchQueue? = nil ) { let uniqueId = UUID() self.id = uniqueId - self.queue = queue ?? DispatchQueue(label: "Fuzzer \(uniqueId)", target: DispatchQueue.global()) + self.queue = + queue ?? DispatchQueue(label: "Fuzzer \(uniqueId)", target: DispatchQueue.global()) self.config = configuration self.events = Events() @@ -226,7 +230,7 @@ public class Fuzzer { } /// Schedule work on this fuzzer's dispatch queue. - public func async(do block: @escaping () -> ()) { + public func async(do block: @escaping () -> Void) { queue.async { guard !self.isStopped else { return } block() @@ -234,7 +238,7 @@ public class Fuzzer { } /// Schedule work on this fuzzer's dispatch queue and wait for its completion. - public func sync(do block: () -> ()) { + public func sync(do block: () -> Void) { queue.sync { guard !self.isStopped else { return } block() @@ -259,7 +263,7 @@ public class Fuzzer { modules[module.name] = module // We only allow one instance of certain modules. - assert(modules.values.filter( { $0 is DistributedFuzzingChildNode }).count <= 1) + assert(modules.values.filter({ $0 is DistributedFuzzingChildNode }).count <= 1) } /// Initializes this fuzzer. @@ -298,7 +302,9 @@ public class Fuzzer { let interval = now.timeIntervalSince(lastCheck) lastCheck = now if interval > 180 { - self.logger.warning("Fuzzer appears unresponsive (watchdog only triggered after \(Int(interval))s instead of 60s).") + self.logger.warning( + "Fuzzer appears unresponsive (watchdog only triggered after \(Int(interval))s instead of 60s)." + ) } } @@ -312,13 +318,17 @@ public class Fuzzer { let percentage = Statistics.percentageOrNa(stub.invocationSuccessRate, 7) let name = stub.name.rightPadded(toLength: nameMaxLength) let invocations = String(format: "%12d", stub.invocationCount) - self.logger.warning("Code generator \(name) might have too restrictive dynamic requirements. Its successful invocation rate is only \(percentage)% after \(invocations) invocations") + self.logger.warning( + "Code generator \(name) might have too restrictive dynamic requirements. Its successful invocation rate is only \(percentage)% after \(invocations) invocations" + ) } if stub.totalSamples >= 100 && stub.correctnessRate! < 0.05 { let name = stub.name.rightPadded(toLength: nameMaxLength) let percentage = Statistics.percentageOrNa(stub.correctnessRate, 7) let totalSamples = String(format: "%10d", stub.totalSamples) - self.logger.warning("Code generator \(name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples") + self.logger.warning( + "Code generator \(name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples" + ) } } } @@ -326,7 +336,9 @@ public class Fuzzer { if template.totalSamples >= 100 && template.correctnessRate! < 0.05 { let percentage = Statistics.percentageOrNa(template.correctnessRate, 7) let totalSamples = String(format: "%10d", template.totalSamples) - self.logger.warning("Program template \(template.name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples") + self.logger.warning( + "Program template \(template.name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples" + ) } } } @@ -414,7 +426,9 @@ public class Fuzzer { } /// Registers a new listener for the given event. - public func registerEventListener(for event: Event, listener: @escaping Event.EventListener) { + public func registerEventListener( + for event: Event, listener: @escaping Event.EventListener + ) { dispatchPrecondition(condition: .onQueue(queue)) event.addListener(listener) } @@ -439,7 +453,9 @@ public class Fuzzer { } private func containsWasm(_ program: Program) -> Bool { - program.code.contains { $0.op.requiredContext.contains(.wasm) || $0.op.requiredContext.contains(.wasmTypeGroup)} + program.code.contains { + $0.op.requiredContext.contains(.wasm) || $0.op.requiredContext.contains(.wasmTypeGroup) + } } /// Imports a potentially interesting program into this fuzzer. @@ -449,7 +465,9 @@ public class Fuzzer { /// When dropout is enabled, a configurable percentage of programs will be ignored during importing. This /// mechanism can help reduce the similarity of different fuzzer instances. @discardableResult - public func importProgram(_ program: Program, origin: ProgramOrigin, enableDropout: Bool = false) -> ImportResult { + public func importProgram( + _ program: Program, origin: ProgramOrigin, enableDropout: Bool = false + ) -> ImportResult { dispatchPrecondition(condition: .onQueue(queue)) if enableDropout && probability(config.dropoutRate) { @@ -460,8 +478,10 @@ public class Fuzzer { if let path = config.storagePath { // Create a folder to store the excluded program if not existent, yet. let dirName = "\(path)/\(Configuration.excludedWasmDirectory)" - try! FileManager.default.createDirectory(atPath: dirName, withIntermediateDirectories: true) - (modules["Storage"] as! Storage).storeProgram(program, + try! FileManager.default.createDirectory( + atPath: dirName, withIntermediateDirectories: true) + (modules["Storage"] as! Storage).storeProgram( + program, as: "program_\(program.id).fzil", in: dirName) } return .needsWasm @@ -474,14 +494,18 @@ public class Fuzzer { case .crashed(let termsig): // Here we explicitly deal with the possibility that an interesting sample // from another instance triggers a crash in this instance. - processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) + processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) case .differential: - processDifferential(program, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin) + processDifferential( + program, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin) case .succeeded: if let aspects = evaluator.evaluate(execution) { - wasImported = processMaybeInteresting(program, havingAspects: aspects, origin: origin) + wasImported = processMaybeInteresting( + program, havingAspects: aspects, origin: origin) } if case .corpusImport(let mode) = origin, mode == .full, !wasImported { @@ -507,10 +531,14 @@ public class Fuzzer { let execution = execute(program, purpose: .programImport) if case .crashed(let termsig) = execution.outcome { - processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) + processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) } else { // Non-deterministic crash - dispatchEvent(events.CrashFound, data: (program, behaviour: .flaky, isUnique: true, origin: origin)) + dispatchEvent( + events.CrashFound, + data: (program, behaviour: .flaky, isUnique: true, origin: origin)) } } @@ -547,7 +575,7 @@ public class Fuzzer { let dummy = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } var variablesToReplaceWithDummy = VariableSet() - b.adopting() { + b.adopting { for instr in program.code { var removeInstruction = false switch instr.op.opcode { @@ -561,7 +589,9 @@ public class Fuzzer { } if !removeInstruction { - let inouts = instr.inouts.map({ variablesToReplaceWithDummy.contains($0) ? dummy : b.adopt($0) }) + let inouts = instr.inouts.map({ + variablesToReplaceWithDummy.contains($0) ? dummy : b.adopt($0) + }) let newInstr = Instruction(instr.op, inouts: inouts, flags: instr.flags) b.append(newInstr) } @@ -583,17 +613,19 @@ public class Fuzzer { /// (e.g. because it throws a runtime exception), then this function will try to "fix" the program so that it /// executes successfully and can be imported. private static let maxProgramImportFixupAttempts = 3 - public func importProgramWithFixup(_ originalProgram: Program, origin: ProgramOrigin) -> (result: ImportResult, fixupAttempts: Int) { + public func importProgramWithFixup(_ originalProgram: Program, origin: ProgramOrigin) -> ( + result: ImportResult, fixupAttempts: Int + ) { var program = originalProgram var result = importProgram(program, origin: origin) // Only attempt fixup if the program failed to execute successfully. In particular, ignore timeouts and // crashes here, but also take into account that not all successfully executing programs will be imported. switch result { - case .dropped, .needsWasm, .imported: - return (result, 0) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 0) + case .failed(_): + break } let b = makeBuilder() @@ -614,13 +646,12 @@ public class Fuzzer { program = removeCallsTo(filteredFunctions, from: program) result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: - return (result, 1) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 1) + case .failed(_): + break } - // Second attempt at fixing the program: enable guards (try-catch) for all guardable operations, then // remove all guards that aren't needed (because no exception is thrown). for instr in program.code { @@ -636,20 +667,21 @@ public class Fuzzer { } result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: - return (result, 2) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 2) + case .failed(_): + break } // Third and final attempt at fixing up the program: simply wrap the entire program in a try-catch block. - b.buildTryCatchFinally(tryBody: { - b.adopting() { - for instr in program.code { - b.adopt(instr) + b.buildTryCatchFinally( + tryBody: { + b.adopting { + for instr in program.code { + b.adopt(instr) + } } - } - }, catchBody: { _ in }) + }, catchBody: { _ in }) program = b.finalize() result = importProgram(program, origin: origin) @@ -662,7 +694,9 @@ public class Fuzzer { /// Corpus import happens asynchronously as it may take a considerable amount of time (each program /// needs to be executed and possibly minimized). During corpus import, the current progress can be /// obtained from corpusImportProgress(). - public func scheduleCorpusImport(_ corpus: [Program], importMode: CorpusImportMode, enableDropout: Bool = false) { + public func scheduleCorpusImport( + _ corpus: [Program], importMode: CorpusImportMode, enableDropout: Bool = false + ) { dispatchPrecondition(condition: .onQueue(queue)) // Currently we only allow corpus import when the fuzzer is still uninitialized. // If necessary, this can be changed, but we'd need to be able to correctly handle the .waiting -> .corpusImport state transition. @@ -703,7 +737,9 @@ public class Fuzzer { /// - timeout: The timeout after which to abort execution. If nil, the default timeout of this fuzzer will be used. /// - purpose: The purpose of this program execution. /// - Returns: An Execution structure representing the execution outcome. - public func execute(_ program: Program, withTimeout timeout: UInt32? = nil, purpose: ExecutionPurpose) -> Execution { + public func execute( + _ program: Program, withTimeout timeout: UInt32? = nil, purpose: ExecutionPurpose + ) -> Execution { dispatchPrecondition(condition: .onQueue(queue)) assert(runner.isInitialized) @@ -713,8 +749,11 @@ public class Fuzzer { let execution = runner.run(script, withTimeout: timeout ?? config.timeout) dispatchEvent(events.PostExecute, data: execution) - if (isDifferentialFuzzing && purpose.supportsDifferentialRun && execution.outcome == .succeeded) { - return executeDifferentialIfNeeded(execution, program, script, withTimeout: timeout ?? config.timeout) + if isDifferentialFuzzing && purpose.supportsDifferentialRun + && execution.outcome == .succeeded + { + return executeDifferentialIfNeeded( + execution, program, script, withTimeout: timeout ?? config.timeout) } return execution @@ -724,7 +763,9 @@ public class Fuzzer { /// This function will first determine which (if any) of the interesting aspects are triggered reliably, then schedule the program for minimization and inclusion in the corpus. /// Returns true if this program was interesting (i.e. had at least some interesting aspects that are triggered reliably), false if not. @discardableResult - func processMaybeInteresting(_ program: Program, havingAspects aspects: ProgramAspects, origin: ProgramOrigin) -> Bool { + func processMaybeInteresting( + _ program: Program, havingAspects aspects: ProgramAspects, origin: ProgramOrigin + ) -> Bool { var aspects = aspects // Determine which (if any) aspects of the program are triggered deterministially. @@ -737,11 +778,13 @@ public class Fuzzer { repeat { attempt += 1 if attempt > maxAttempts { - logger.warning("Sample did not converage after \(maxAttempts) attempts. Discarding it") + logger.warning( + "Sample did not converage after \(maxAttempts) attempts. Discarding it") return false } - guard let intersection = evaluator.computeAspectIntersection(of: program, with: aspects) else { + guard let intersection = evaluator.computeAspectIntersection(of: program, with: aspects) + else { // This likely means that no aspects are triggered deterministically, so discard this sample. return false } @@ -763,7 +806,8 @@ public class Fuzzer { if origin == .local { program.comments.add("Program is interesting due to \(aspects)", at: .footer) } else { - program.comments.add("Imported program is interesting due to \(aspects)", at: .footer) + program.comments.add( + "Imported program is interesting due to \(aspects)", at: .footer) } } assert(!program.code.contains(where: { $0.op is JsInternalOperation })) @@ -781,7 +825,9 @@ public class Fuzzer { // Minimization should be performed as part of the fuzzing dispatch group. This way, the next fuzzing iteration // will only start once the curent sample has been fully processed and inserted into the corpus. fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: aspects, limit: config.minimizationLimit) { minimizedProgram in + minimizer.withMinimizedCopy( + program, withAspects: aspects, limit: config.minimizationLimit + ) { minimizedProgram in self.fuzzGroup.leave() finishProcessing(minimizedProgram) } @@ -790,7 +836,10 @@ public class Fuzzer { } /// Collect information about a crash. - func collectCrashInfo(for program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, withExectime exectime: TimeInterval) -> [String] { + func collectCrashInfo( + for program: Program, withSignal termsig: Int, withStderr stderr: String, + withStdout stdout: String, withExectime exectime: TimeInterval + ) -> [String] { var info = [String]() info.append("CRASH INFO") info.append("==========") @@ -804,24 +853,33 @@ public class Fuzzer { info.append(stdout.trimmingCharacters(in: .newlines)) info.append("FUZZER ARGS: \(config.arguments.joined(separator: " "))") info.append("TARGET ARGS: \(runner.processArguments.joined(separator: " "))") - info.append("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") + info.append( + "CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") info.append("EXECUTION TIME: \(Int(exectime * 1000))ms") return info } /// Process a program that causes a crash. - func processCrash(_ program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval) { + func processCrash( + _ program: Program, withSignal termsig: Int, withStderr stderr: String, + withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval + ) { func processCommon(_ program: Program) { let hasCrashInfo = program.comments.at(.footer)?.contains("CRASH INFO") ?? false if !hasCrashInfo { - for line in collectCrashInfo(for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, withExectime: exectime) { + for line in collectCrashInfo( + for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, + withExectime: exectime) + { program.comments.add(line, at: .footer) } } assert(program.comments.at(.footer)?.contains("CRASH INFO") ?? false) // Check for uniqueness only after minimization - let execution = execute(program, withTimeout: self.config.timeout * 2, purpose: .checkForDeterministicBehavior) + let execution = execute( + program, withTimeout: self.config.timeout * 2, + purpose: .checkForDeterministicBehavior) if case .crashed = execution.outcome { let isUnique = evaluator.evaluateCrash(execution) != nil dispatchEvent(events.CrashFound, data: (program, .deterministic, isUnique, origin)) @@ -835,14 +893,19 @@ public class Fuzzer { } fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .crashed(termsig))) { minimizedProgram in + minimizer.withMinimizedCopy( + program, withAspects: ProgramAspects(outcome: .crashed(termsig)) + ) { minimizedProgram in self.fuzzGroup.leave() processCommon(minimizedProgram) } } /// Process a program that causes difference between optimized and unoptimized executions - func processDifferential(_ program: Program, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin) { + func processDifferential( + _ program: Program, withStderr stderr: String, withStdout stdout: String, + origin: ProgramOrigin + ) { func processCommon(_ program: Program) { let hasDiffInfo = program.comments.at(.footer)?.contains("DIFFERENTIAL INFO") ?? false if !hasDiffInfo { @@ -858,9 +921,12 @@ public class Fuzzer { program.comments.add(footerMessage, at: .footer) } - let execution = execute(program, withTimeout: self.config.timeout * 2, purpose: .checkForDeterministicBehavior) + let execution = execute( + program, withTimeout: self.config.timeout * 2, + purpose: .checkForDeterministicBehavior) if case .differential = execution.outcome { - dispatchEvent(events.DifferentialFound, data: (program, .deterministic, true, origin)) + dispatchEvent( + events.DifferentialFound, data: (program, .deterministic, true, origin)) } else { dispatchEvent(events.DifferentialFound, data: (program, .flaky, true, origin)) } @@ -871,7 +937,8 @@ public class Fuzzer { } fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { minimizedProgram in + minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { + minimizedProgram in self.fuzzGroup.leave() processCommon(minimizedProgram) } @@ -924,34 +991,67 @@ public class Fuzzer { let program = currentCorpusImportJob.nextProgram() if currentCorpusImportJob.numberOfProgramsProcessedSoFar % 500 == 0 { - logger.info("Corpus import progress: processed \(currentCorpusImportJob.numberOfProgramsProcessedSoFar) of \(currentCorpusImportJob.totalNumberOfProgramsToImport) programs") + logger.info( + "Corpus import progress: processed \(currentCorpusImportJob.numberOfProgramsProcessedSoFar) of \(currentCorpusImportJob.totalNumberOfProgramsToImport) programs" + ) } - let (result, fixupAttempts) = importProgramWithFixup(program, origin: .corpusImport(mode: currentCorpusImportJob.importMode)) + let (result, fixupAttempts) = importProgramWithFixup( + program, origin: .corpusImport(mode: currentCorpusImportJob.importMode)) currentCorpusImportJob.notifyImportOutcome(result, fixupAttempts: fixupAttempts) if currentCorpusImportJob.isFinished { logger.info("Corpus import finished:") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs executed successfully") - logger.info(" Of which \(currentCorpusImportJob.numberOfProgramsThatWereImport) programs were added to the corpus") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatNeededFixup)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs needed fixup during import") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededOneFixupAttempt) succeeded after attempt 1") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededTwoFixupAttempts) succeeded after attempt 2") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededThreeFixupAttempts) succeeded after attempt 3") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatFailedDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs failed to execute (even after fixup) and weren't imported") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatTimedOutDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs timed out and weren't imported") + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs executed successfully" + ) + logger.info( + " Of which \(currentCorpusImportJob.numberOfProgramsThatWereImport) programs were added to the corpus" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatNeededFixup)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs needed fixup during import" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededOneFixupAttempt) succeeded after attempt 1" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededTwoFixupAttempts) succeeded after attempt 2" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededThreeFixupAttempts) succeeded after attempt 3" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatFailedDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs failed to execute (even after fixup) and weren't imported" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatTimedOutDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs timed out and weren't imported" + ) if !config.isWasmEnabled { - logger.info("\(currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require Wasm which is disabled") - if currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled > 0 && config.storagePath != nil { - logger.info(" These programs have been stored at \(config.storagePath!)/\(Configuration.excludedWasmDirectory)/") + logger.info( + "\(currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require Wasm which is disabled" + ) + if currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled > 0 + && config.storagePath != nil + { + logger.info( + " These programs have been stored at \(config.storagePath!)/\(Configuration.excludedWasmDirectory)/" + ) } } - let successRatio = Double(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport) / Double(currentCorpusImportJob.totalNumberOfProgramsToImport) + let successRatio = + Double( + currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport) + / Double(currentCorpusImportJob.totalNumberOfProgramsToImport) let failureRatio = 1.0 - successRatio if failureRatio >= 0.25 { - let reason = config.isWasmEnabled ? "execute successfully" : "execute successfully or require currently disabled wasm" - logger.warning("\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported.") + let reason = + config.isWasmEnabled + ? "execute successfully" + : "execute successfully or require currently disabled wasm" + logger.warning( + "\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported." + ) } dispatchEvent(events.CorpusImportComplete) @@ -971,9 +1071,13 @@ public class Fuzzer { // have finished the initial corpus generation), then compare the corpus size and coverage. if iterationsSinceLastInterestingProgram > 100 { guard !corpus.isEmpty else { - logger.fatal("Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?") + logger.fatal( + "Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?" + ) } - logger.info("Initial corpus generation finished. Corpus now contains \(corpus.size) elements") + logger.info( + "Initial corpus generation finished. Corpus now contains \(corpus.size) elements" + ) changeState(to: .fuzzing) } @@ -1013,13 +1117,15 @@ public class Fuzzer { /// Runs a number of startup tests to check whether everything is configured correctly. /// Returns a recommended timeout. - public func runStartupTests(with timeout : Timeout) -> Timeout { + public func runStartupTests(with timeout: Timeout) -> Timeout { assert(isInitialized) // Check if we can execute programs var execution = execute(Program(), purpose: .startup) guard case .succeeded = execution.outcome else { - logger.fatal("Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?") + logger.fatal( + "Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?" + ) } // Check if we can detect failed executions (i.e. an exception was thrown) @@ -1028,7 +1134,9 @@ public class Fuzzer { b.throwException(exception) execution = execute(b.finalize(), purpose: .startup) guard case .failed = execution.outcome else { - logger.fatal("Cannot detect failed executions (exit code must be nonzero when an uncaught exception was thrown, but execution outcome was \(execution.outcome))") + logger.fatal( + "Cannot detect failed executions (exit code must be nonzero when an uncaught exception was thrown, but execution outcome was \(execution.outcome))" + ) } var maxExecutionTime: TimeInterval = 0 @@ -1047,19 +1155,22 @@ public class Fuzzer { execution = execute(b.finalize(), purpose: .startup) if execution.outcome == .timedOut { - logger.fatal("Testcase \"\(test)\" timed out, the configured timeout threshold " - + "(\(config.timeout)ms) might be too low") + logger.fatal( + "Testcase \"\(test)\" timed out, the configured timeout threshold " + + "(\(config.timeout)ms) might be too low") } switch expectedResult { case .shouldSucceed where execution.outcome != .succeeded: - logger.fatal("Testcase \"\(test)\" did not execute successfully" + - "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") + logger.fatal( + "Testcase \"\(test)\" did not execute successfully" + + "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") case .shouldCrash where !execution.outcome.isCrash(): logger.fatal("Testcase \"\(test)\" did not crash") case .shouldNotCrash where execution.outcome.isCrash(): - logger.fatal("Testcase \"\(test)\" unexpectedly crashed" + - "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") + logger.fatal( + "Testcase \"\(test)\" unexpectedly crashed" + + "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") default: // Test passed break @@ -1074,7 +1185,9 @@ public class Fuzzer { } if !hasAnyCrashTests { - logger.warning("Cannot check if crashes are detected as there are no startup tests that should cause a crash") + logger.warning( + "Cannot check if crashes are detected as there are no startup tests that should cause a crash" + ) } // Determine recommended timeout value (rounded up to nearest multiple of 10ms) @@ -1082,10 +1195,12 @@ public class Fuzzer { let recommendedTimeout = 2 * maxExecutionTimeMs // Specify the actual timeout based on an interval if configured. - let actualTimeout : Timeout + let actualTimeout: Timeout if case .interval(let lowerLimit, let upperLimit) = timeout { let timeout = max(min(UInt32(recommendedTimeout), upperLimit), lowerLimit) - logger.info("Determined a timeout of \(timeout)ms based on the interval [\(lowerLimit), \(upperLimit)]") + logger.info( + "Determined a timeout of \(timeout)ms based on the interval [\(lowerLimit), \(upperLimit)]" + ) actualTimeout = Timeout.value(timeout) // Update the configuration used by the main thread. Worker threads @@ -1095,15 +1210,19 @@ public class Fuzzer { actualTimeout = timeout } - logger.info("Recommended timeout: at least \(recommendedTimeout)ms. Current timeout: \(config.timeout)ms") + logger.info( + "Recommended timeout: at least \(recommendedTimeout)ms. Current timeout: \(config.timeout)ms" + ) // Check if we can receive program output b = makeBuilder() let str = b.loadString("Hello World!") b.doPrint(str) - let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters(in: .whitespacesAndNewlines) + let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters( + in: .whitespacesAndNewlines) if output != "Hello World!" { - logger.warning("Cannot receive FuzzIL output (got \"\(output)\" instead of \"Hello World!\")") + logger.warning( + "Cannot receive FuzzIL output (got \"\(output)\" instead of \"Hello World!\")") } // Wrap the executor in a JavaScriptTestRunner @@ -1114,8 +1233,10 @@ public class Fuzzer { do { let output = try executor.executeScript("", withTimeout: 300).output if output.lengthOfBytes(using: .utf8) > 0 { - logger.warning("Runner has non-empty output for empty program! This might indicate that some flags are wrong.") - logger.warning("Output:\n\(output)" ) + logger.warning( + "Runner has non-empty output for empty program! This might indicate that some flags are wrong." + ) + logger.warning("Output:\n\(output)") } } catch { logger.warning("Could not run shell in standalone mode to check flags.") @@ -1125,7 +1246,9 @@ public class Fuzzer { return actualTimeout } - private func executeDifferentialIfNeeded(_ execution: Execution, _ program: Program, _ script: String, withTimeout timeout: UInt32) -> Execution { + private func executeDifferentialIfNeeded( + _ execution: Execution, _ program: Program, _ script: String, withTimeout timeout: UInt32 + ) -> Execution { do { let optPath = config.diffConfig!.getDumpFilename(isOptimized: true) let unoptPath = config.diffConfig!.getDumpFilename(isOptimized: false) @@ -1148,14 +1271,17 @@ public class Fuzzer { let unoptimizedDump = try String(contentsOfFile: unoptPath, encoding: .utf8) // While Dumpling is not super-stable we print out the program here to not miss anything. - let result = DiffExecution.diff(optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, unoptDumpOut: unoptimizedDump) + let result = DiffExecution.diff( + optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, + unoptDumpOut: unoptimizedDump) if result.outcome == .differential { - logger.error(""" - ================================================================ - [DUMPLING] POTENTIAL DIFFERENTIAL DETECTED - ================================================================ - """) + logger.error( + """ + ================================================================ + [DUMPLING] POTENTIAL DIFFERENTIAL DETECTED + ================================================================ + """) logger.error(script) } @@ -1189,11 +1315,13 @@ public class Fuzzer { var numberOfProgramsThatNeededFixup: Int { assert(Fuzzer.maxProgramImportFixupAttempts == 3) - return numberOfProgramsThatNeededOneFixupAttempt + numberOfProgramsThatNeededTwoFixupAttempts + numberOfProgramsThatNeededThreeFixupAttempts + return numberOfProgramsThatNeededOneFixupAttempt + + numberOfProgramsThatNeededTwoFixupAttempts + + numberOfProgramsThatNeededThreeFixupAttempts } init(corpus: [Program], mode: CorpusImportMode) { - self.corpusToImport = corpus.reversed() // Programs are taken from the end. + self.corpusToImport = corpus.reversed() // Programs are taken from the end. self.importMode = mode self.totalNumberOfProgramsToImport = corpus.count } diff --git a/Sources/Fuzzilli/Lifting/Expression.swift b/Sources/Fuzzilli/Lifting/Expression.swift index ff149fdcb..c748ed2a4 100644 --- a/Sources/Fuzzilli/Lifting/Expression.swift +++ b/Sources/Fuzzilli/Lifting/Expression.swift @@ -84,9 +84,10 @@ public struct Expression: CustomStringConvertible { } func extended(by part: String) -> Expression { - return Expression(type: type, - text: text + part, - numSubexpressions: numSubexpressions) + return Expression( + type: type, + text: text + part, + numSubexpressions: numSubexpressions) } func extended(by part: Expression) -> Expression { @@ -96,20 +97,21 @@ public struct Expression: CustomStringConvertible { } else { newText = text + part.text } - return Expression(type: type, - text: newText, - numSubexpressions: numSubexpressions + 1) + return Expression( + type: type, + text: newText, + numSubexpressions: numSubexpressions + 1) } - static func +(lhs: Expression, rhs: Expression) -> Expression { + static func + (lhs: Expression, rhs: Expression) -> Expression { return lhs.extended(by: rhs) } - static func +(lhs: Expression, rhs: String) -> Expression { + static func + (lhs: Expression, rhs: String) -> Expression { return lhs.extended(by: rhs) } - static func +(lhs: Expression, rhs: Int64) -> Expression { + static func + (lhs: Expression, rhs: Int64) -> Expression { return lhs.extended(by: String(rhs)) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index b624f08a4..4dffd0123 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -23,7 +23,7 @@ public class FuzzILLifter: Lifter { return "v\(v.number)" } - private func lift(_ instr : Instruction, with w: inout ScriptWriter) { + private func lift(_ instr: Instruction, with w: inout ScriptWriter) { func input(_ n: Int) -> String { return lift(instr.input(n)) } @@ -73,16 +73,22 @@ public class FuzzILLifter: Lifter { case .createNamedVariable(let op): if op.hasInitialValue { - w.emit("\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)', \(input(0))") + w.emit( + "\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)', \(input(0))" + ) } else { - w.emit("\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)'") + w.emit( + "\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)'" + ) } case .createNamedDisposableVariable(let op): w.emit("\(output()) <- CreateNamedDisposableVariable '\(op.variableName)', \(input(0))") case .createNamedAsyncDisposableVariable(let op): - w.emit("\(output()) <- CreateNamedAsyncDisposableVariable '\(op.variableName)', \(input(0))") + w.emit( + "\(output()) <- CreateNamedAsyncDisposableVariable '\(op.variableName)', \(input(0))" + ) case .loadDisposableVariable: w.emit("\(output()) <- LoadDisposableVariable \(input(0))") @@ -171,15 +177,15 @@ public class FuzzILLifter: Lifter { let type = op.isExpression ? "exp" : "decl" var line = "\(output()) <- BeginClassDefinition (\(type))" if op.hasSuperclass { - line += " \(input(0))" + line += " \(input(0))" } w.emit(line) w.increaseIndentionLevel() case .beginClassConstructor: - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassConstructor -> \(params)") - w.increaseIndentionLevel() + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassConstructor -> \(params)") + w.increaseIndentionLevel() case .endClassConstructor: w.decreaseIndentionLevel() @@ -295,8 +301,8 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassPrivateMethod") case .endClassDefinition: - w.decreaseIndentionLevel() - w.emit("EndClassDefinition") + w.decreaseIndentionLevel() + w.emit("EndClassDefinition") case .createArray: let elems = instr.inputs.map(lift).joined(separator: ", ") @@ -340,7 +346,9 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.propertyName)'") case .configureProperty(let op): - w.emit("ConfigureProperty \(input(0)), '\(op.propertyName)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]") + w.emit( + "ConfigureProperty \(input(0)), '\(op.propertyName)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]" + ) case .getElement(let op): let opcode = op.isGuarded ? "GetElement (guarded)" : "GetElement" @@ -357,7 +365,9 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.index)'") case .configureElement(let op): - w.emit("ConfigureElement \(input(0)), '\(op.index)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]") + w.emit( + "ConfigureElement \(input(0)), '\(op.index)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]" + ) case .getComputedProperty(let op): let opcode = op.isGuarded ? "GetComputedProperty (guarded)" : "GetComputedProperty" @@ -370,11 +380,14 @@ public class FuzzILLifter: Lifter { w.emit("UpdateComputedProperty \(input(0)), \(input(1)), '\(op.op.token)',\(input(2))") case .deleteComputedProperty(let op): - let opcode = op.isGuarded ? "DeleteComputedProperty (guarded)" : "DeleteComputedProperty" + let opcode = + op.isGuarded ? "DeleteComputedProperty (guarded)" : "DeleteComputedProperty" w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1))") case .configureComputedProperty(let op): - w.emit("ConfigureComputedProperty \(input(0)), \(input(1)), '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 2).map(lift))]") + w.emit( + "ConfigureComputedProperty \(input(0)), \(input(1)), '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 2).map(lift))]" + ) case .typeOf: w.emit("\(output()) <- TypeOf \(input(0))") @@ -389,21 +402,21 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- TestIn \(input(0)), \(input(1))") case .beginPlainFunction(let op as BeginAnyFunction), - .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + .beginArrowFunction(let op as BeginAnyFunction), + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") w.emit("\(output()) <- \(op.name) -> \(params)") w.increaseIndentionLevel() case .endPlainFunction(let op as EndAnyFunction), - .endArrowFunction(let op as EndAnyFunction), - .endGeneratorFunction(let op as EndAnyFunction), - .endAsyncFunction(let op as EndAnyFunction), - .endAsyncArrowFunction(let op as EndAnyFunction), - .endAsyncGeneratorFunction(let op as EndAnyFunction): + .endArrowFunction(let op as EndAnyFunction), + .endGeneratorFunction(let op as EndAnyFunction), + .endAsyncFunction(let op as EndAnyFunction), + .endAsyncArrowFunction(let op as EndAnyFunction), + .endAsyncGeneratorFunction(let op as EndAnyFunction): w.decreaseIndentionLevel() w.emit("\(op.name)") @@ -441,35 +454,54 @@ public class FuzzILLifter: Lifter { case .callFunction(let op): let opcode = op.isGuarded ? "CallFunction (guarded)" : "CallFunction" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .callFunctionWithSpread(let op): - let opcode = op.isGuarded ? "CallFunctionWithSpread (guarded)" : "CallFunctionWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + let opcode = + op.isGuarded ? "CallFunctionWithSpread (guarded)" : "CallFunctionWithSpread" + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .construct(let op): let opcode = op.isGuarded ? "Construct (guarded)" : "Construct" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .constructWithSpread(let op): let opcode = op.isGuarded ? "ConstructWithSpread (guarded)" : "ConstructWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .callMethod(let op): let opcode = op.isGuarded ? "CallMethod (guarded)" : "CallMethod" - w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .callMethodWithSpread(let op): let opcode = op.isGuarded ? "CallMethodWithSpread (guarded)" : "CallMethodWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .callComputedMethod(let op): let opcode = op.isGuarded ? "CallComputedMethod (guarded)" : "CallComputedMethod" - w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .callComputedMethodWithSpread(let op): - let opcode = op.isGuarded ? "CallComputedMethodWithSpread (guarded)" : "CallComputedMethodWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + let opcode = + op.isGuarded + ? "CallComputedMethodWithSpread (guarded)" : "CallComputedMethodWithSpread" + w.emit( + "\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .unaryOperation(let op): if op.op.isPostfix { @@ -495,19 +527,27 @@ public class FuzzILLifter: Lifter { case .destructArray(let op): let outputs = instr.outputs.map(lift) - w.emit("[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArray \(input(0))") + w.emit( + "[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArray \(input(0))" + ) case .destructArrayAndReassign(let op): let outputs = instr.inputs.dropFirst().map(lift) - w.emit("[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArrayAndReassign \(input(0))") + w.emit( + "[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArrayAndReassign \(input(0))" + ) case .destructObject(let op): let outputs = instr.outputs.map(lift) - w.emit("{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObject \(input(0))") + w.emit( + "{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObject \(input(0))" + ) case .destructObjectAndReassign(let op): let outputs = instr.inputs.dropFirst().map(lift) - w.emit("{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObjectAndReassign \(input(0))") + w.emit( + "{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObjectAndReassign \(input(0))" + ) case .compare(let op): w.emit("\(output()) <- Compare \(input(0)), '\(op.op.token)', \(input(1))") @@ -580,28 +620,32 @@ public class FuzzILLifter: Lifter { w.emit("EndSwitch") case .callSuperConstructor: - w.emit("CallSuperConstructor [\(liftCallArguments(instr.variadicInputs))]") + w.emit("CallSuperConstructor [\(liftCallArguments(instr.variadicInputs))]") case .callSuperMethod(let op): - w.emit("\(output()) <- CallSuperMethod '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- CallSuperMethod '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .getPrivateProperty(let op): - w.emit("\(output()) <- GetPrivateProperty '\(op.propertyName)'") + w.emit("\(output()) <- GetPrivateProperty '\(op.propertyName)'") case .setPrivateProperty(let op): - w.emit("SetPrivateProperty '\(op.propertyName)', \(input(0))") + w.emit("SetPrivateProperty '\(op.propertyName)', \(input(0))") case .updatePrivateProperty(let op): w.emit("UpdatePrivateProperty '\(op.propertyName)', '\(op.op.token)', \(input(0))") case .callPrivateMethod(let op): - w.emit("\(output()) <- CallPrivateMethod \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- CallPrivateMethod \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .getSuperProperty(let op): - w.emit("\(output()) <- GetSuperProperty '\(op.propertyName)'") + w.emit("\(output()) <- GetSuperProperty '\(op.propertyName)'") case .setSuperProperty(let op): - w.emit("SetSuperProperty '\(op.propertyName)', \(input(0))") + w.emit("SetSuperProperty '\(op.propertyName)', \(input(0))") case .getComputedSuperProperty(_): w.emit("\(output()) <- GetComputedSuperProperty \(input(0))") @@ -690,7 +734,9 @@ public class FuzzILLifter: Lifter { case .beginForOfLoopWithDestruct(let op): let outputs = instr.innerOutputs.map(lift) - w.emit("BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))]") + w.emit( + "BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))]" + ) w.increaseIndentionLevel() case .endForOfLoop: @@ -710,7 +756,7 @@ public class FuzzILLifter: Lifter { w.emit("EndRepeatLoop") case .loopBreak, - .switchBreak: + .switchBreak: w.emit("Break") case .loopContinue: @@ -765,14 +811,18 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- EndWasmModule") case .createWasmGlobal(let op): - let isMutable = op.isMutable ? ", mutable" : "" - w.emit("\(output()) <- CreateWasmGlobal \(op.value.typeString()): \(op.value.valueToString())\(isMutable)") + let isMutable = op.isMutable ? ", mutable" : "" + w.emit( + "\(output()) <- CreateWasmGlobal \(op.value.typeString()): \(op.value.valueToString())\(isMutable)" + ) case .createWasmMemory(let op): let maxPagesStr = op.memType.limits.max != nil ? "\(op.memType.limits.max!)" : "" let isMem64Str = op.memType.isMemory64 ? " memory64" : "" let sharedStr = op.memType.isShared ? " shared" : "" - w.emit("\(output()) <- CreateWasmMemory [\(op.memType.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)") + w.emit( + "\(output()) <- CreateWasmMemory [\(op.memType.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)" + ) case .createWasmTable(let op): var maxSizeStr = "" @@ -780,7 +830,9 @@ public class FuzzILLifter: Lifter { maxSizeStr = "\(maxSize)" } let isTable64Str = op.tableType.isTable64 ? ", table64" : "" - w.emit("\(output()) <- CreateWasmTable \(op.tableType.elementType) [\(op.tableType.limits.min),\(maxSizeStr)\(isTable64Str)]") + w.emit( + "\(output()) <- CreateWasmTable \(op.tableType.elementType) [\(op.tableType.limits.min),\(maxSizeStr)\(isTable64Str)]" + ) case .createWasmJSTag(_): w.emit("\(output()) <- CreateWasmJSTag") @@ -805,7 +857,9 @@ public class FuzzILLifter: Lifter { case .beginWasmFunction(_): // TODO(cffsmith): do this properly? - w.emit("BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .endWasmFunction: @@ -821,7 +875,9 @@ public class FuzzILLifter: Lifter { "\(entry) : \(input(index))" }.joined(separator: ", ") let isTable64Str = op.isTable64 ? ", table64" : "" - w.emit("\(output()) <- WasmDefineTable \(op.elementType)\(isTable64Str), (\(op.limits.min), \(String(describing: op.limits.max))), [\(entries)]") + w.emit( + "\(output()) <- WasmDefineTable \(op.elementType)\(isTable64Str), (\(op.limits.min), \(String(describing: op.limits.max))), [\(entries)]" + ) case .wasmDefineElementSegment(_): w.emit("\(output()) <- WasmDefineElementSegment [...]") @@ -841,7 +897,9 @@ public class FuzzILLifter: Lifter { let maxPagesStr = mem.limits.max != nil ? "\(mem.limits.max!)" : "" let isMem64Str = mem.isMemory64 ? " memory64" : "" let sharedStr = mem.isShared ? " shared" : "" - w.emit("\(output()) <- WasmDefineMemory [\(mem.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)") + w.emit( + "\(output()) <- WasmDefineMemory [\(mem.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)" + ) case .wasmDefineDataSegment(_): w.emit("\(output()) <- WasmDefineDataSegment [...]") @@ -865,22 +923,34 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmTableGrow \(input(0)), \(input(1)), \(input(2))") case .wasmMemoryLoad(let op): - w.emit("\(output()) <- WasmMemoryLoad '\(op.loadType)' \(input(0))[\(input(1)) + \(op.staticOffset)]") + w.emit( + "\(output()) <- WasmMemoryLoad '\(op.loadType)' \(input(0))[\(input(1)) + \(op.staticOffset)]" + ) case .wasmMemoryStore(let op): - w.emit("WasmMemoryStore '\(op.storeType)' \(input(0))[\(input(1)) + \(op.staticOffset)] <- \(input(2))") + w.emit( + "WasmMemoryStore '\(op.storeType)' \(input(0))[\(input(1)) + \(op.staticOffset)] <- \(input(2))" + ) case .wasmAtomicLoad(let op): - w.emit("\(output()) <- WasmAtomicLoad \(input(0))[\(input(1)) + \(op.offset)] [\(op.loadType)]") + w.emit( + "\(output()) <- WasmAtomicLoad \(input(0))[\(input(1)) + \(op.offset)] [\(op.loadType)]" + ) case .wasmAtomicStore(let op): - w.emit("WasmAtomicStore \(input(0))[\(input(1)) + \(op.offset)] <- \(input(2)) [\(op.storeType)]") + w.emit( + "WasmAtomicStore \(input(0))[\(input(1)) + \(op.offset)] <- \(input(2)) [\(op.storeType)]" + ) case .wasmAtomicRMW(let op): - w.emit("\(output()) <- WasmAtomicRMW \(input(0))[\(input(1)) + \(op.offset)] \(op.op) \(input(2))") + w.emit( + "\(output()) <- WasmAtomicRMW \(input(0))[\(input(1)) + \(op.offset)] \(op.op) \(input(2))" + ) case .wasmAtomicCmpxchg(let op): - w.emit("\(output()) <- WasmAtomicCmpxchg \(input(0))[\(input(1)) + \(op.offset)], \(input(2)), \(input(3)) [\(op.op)]") + w.emit( + "\(output()) <- WasmAtomicCmpxchg \(input(0))[\(input(1)) + \(op.offset)], \(input(2)), \(input(3)) [\(op.op)]" + ) case .wasmMemorySize(_): w.emit("\(output()) <- WasmMemorySize \(input(0))") @@ -961,25 +1031,43 @@ public class FuzzILLifter: Lifter { case .wasmWrapi64Toi32(_): w.emit("\(output()) <- WasmWrapi64Toi32 \(input(0))") case .wasmTruncatef32Toi32(let op): - w.emit("\(output()) <- WasmTruncatef32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef64Toi32(let op): - w.emit("\(output()) <- WasmTruncatef64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmExtendi32Toi64(let op): - w.emit("\(output()) <- WasmExtendi32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmExtendi32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef32Toi64(let op): - w.emit("\(output()) <- WasmTruncatef32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef64Toi64(let op): - w.emit("\(output()) <- WasmTruncatef64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti32Tof32(let op): - w.emit("\(output()) <- WasmConverti32Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti32Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti64Tof32(let op): - w.emit("\(output()) <- WasmConverti64Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti64Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmDemotef64Tof32(_): w.emit("\(output()) <- WasmDemotef64Tof32 \(input(0))") case .wasmConverti32Tof64(let op): - w.emit("\(output()) <- WasmConverti32Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti32Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti64Tof64(let op): - w.emit("\(output()) <- WasmConverti64Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti64Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmPromotef32Tof64(_): w.emit("\(output()) <- WasmPromotef32Tof64 \(input(0))") case .wasmReinterpretf32Asi32(_): @@ -1001,13 +1089,21 @@ public class FuzzILLifter: Lifter { case .wasmSignExtend32Intoi64(_): w.emit("\(output()) <- WasmSignExtend32Intoi64 \(input(0))") case .wasmTruncateSatf32Toi32(let op): - w.emit("\(output()) <- WasmTruncateSatf32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf64Toi32(let op): - w.emit("\(output()) <- WasmTruncateSatf64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf32Toi64(let op): - w.emit("\(output()) <- WasmTruncateSatf32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf64Toi64(let op): - w.emit("\(output()) <- WasmTruncateSatf64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmReturn(let op): if op.numInputs > 0 { @@ -1025,7 +1121,9 @@ public class FuzzILLifter: Lifter { if op.outputCount == 0 { w.emit("WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]") } else { - w.emit("\(output()) <- WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]") + w.emit( + "\(output()) <- WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]" + ) } case .wasmCallIndirect(let op): @@ -1057,7 +1155,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginBlock(_): // TODO(cffsmith): Maybe lift labels as e.g. L7 or something like that? let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginBlock [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginBlock [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndBlock(let op): @@ -1072,7 +1172,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginLoop(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginLoop [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginLoop [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndLoop(let op): @@ -1088,9 +1190,11 @@ public class FuzzILLifter: Lifter { case .wasmBeginTryTable(let op): let args = instr.inputs.map(lift) let blockArgs = args.prefix(1 + op.parameterCount).joined(separator: ", ") - w.emit("WasmBeginTryTable [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTryTable [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel(by: 2) - var inputIndex = 1 + op.parameterCount + var inputIndex = 1 + op.parameterCount op.catches.forEach { kind in if kind == .Ref || kind == .NoRef { w.emit("catching \(kind) \(args[inputIndex]) to \(args[inputIndex + 1])") @@ -1114,7 +1218,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginTry(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginTry [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTry [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmBeginCatchAll(_): @@ -1127,7 +1233,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginCatch(_): assert(instr.numOutputs == 0) w.decreaseIndentionLevel() - w.emit("WasmBeginCatch \(input(0)) [\(instr.numInputs > 1 ? input(1) : "")] -> L:\(instr.innerOutput(0)) E:\(instr.innerOutput(1)) [\(liftCallArguments(instr.innerOutputs(2...)))]") + w.emit( + "WasmBeginCatch \(input(0)) [\(instr.numInputs > 1 ? input(1) : "")] -> L:\(instr.innerOutput(0)) E:\(instr.innerOutput(1)) [\(liftCallArguments(instr.innerOutputs(2...)))]" + ) w.increaseIndentionLevel() case .wasmEndTry(let op): @@ -1150,7 +1258,9 @@ public class FuzzILLifter: Lifter { w.emit("WasmRethrow \(instr.input(0))") case .wasmBeginTryDelegate(_): - w.emit("WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndTryDelegate(_): @@ -1170,35 +1280,44 @@ public class FuzzILLifter: Lifter { w.emit("WasmBranch: \(instr.inputs.map(lift).joined(separator: ", "))") case .wasmBranchIf(let op): - let hint = switch op.hint { + let hint = + switch op.hint { case .None: "" case .Likely: "likely " case .Unlikely: "unlikely " - } + } let condition = instr.inputs.last! let label = instr.inputs.first! let args = instr.inputs.dropFirst().dropLast().map(lift) w.emit("WasmBranchIf \(hint)\(condition) to \(label) [\(args.joined(separator: ", "))]") case .wasmBranchTable(let op): - let table = (0.. \(instr.input($1)), "}.joined() + let table = + (0.. \(instr.input($1)), " }.joined() + "default => \(instr.input(op.valueCount))" - w.emit("WasmBranchTable on \(instr.input(op.valueCount+1)) [\(table)] args: \(Array(instr.inputs)[(op.valueCount+2)...])") + w.emit( + "WasmBranchTable on \(instr.input(op.valueCount+1)) [\(table)] args: \(Array(instr.inputs)[(op.valueCount+2)...])" + ) case .wasmBeginIf(let op): let inputs = instr.inputs.map(lift).joined(separator: ", ") - let hint = switch op.hint { + let hint = + switch op.hint { case .None: "" case .Likely: "likely " case .Unlikely: "unlikely " - } - w.emit("WasmBeginIf \(op.inverted ? "inverted " : "")\(hint) [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + } + w.emit( + "WasmBeginIf \(op.inverted ? "inverted " : "")\(hint) [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmBeginElse(_): w.decreaseIndentionLevel() let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginElse [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginElse [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndIf(let op): @@ -1230,22 +1349,32 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmSimd128IntegerUnOp \(op.shape) \(op.unOpKind) \(input(0))") case .wasmSimd128IntegerBinOp(let op): - w.emit("\(output()) <- WasmSimd128IntegerBinOp \(op.shape) \(op.binOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128IntegerBinOp \(op.shape) \(op.binOpKind) \(input(0)) \(input(1))" + ) case .wasmSimd128IntegerTernaryOp(let op): - w.emit("\(output()) <- WasmSimd128IntegerTernaryOp \(op.shape) \(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))") + w.emit( + "\(output()) <- WasmSimd128IntegerTernaryOp \(op.shape) \(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))" + ) case .wasmSimd128FloatUnOp(let op): w.emit("\(output()) <- WasmSimd128FloatUnOp \(op.shape).\(op.unOpKind) \(input(0))") case .wasmSimd128FloatBinOp(let op): - w.emit("\(output()) <- WasmSimd128FloatBinOp \(op.shape).\(op.binOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128FloatBinOp \(op.shape).\(op.binOpKind) \(input(0)) \(input(1))" + ) case .wasmSimd128FloatTernaryOp(let op): - w.emit("\(output()) <- WasmSimd128FloatTernaryOp \(op.shape).\(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))") + w.emit( + "\(output()) <- WasmSimd128FloatTernaryOp \(op.shape).\(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))" + ) case .wasmSimd128Compare(let op): - w.emit("\(output()) <- WasmSimd128Compare \(op.shape) \(op.compareOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128Compare \(op.shape) \(op.compareOpKind) \(input(0)) \(input(1))" + ) case .wasmSimdSplat(let op): w.emit("\(output()) <- WasmSimdSplat \(op.kind) \(input(0))") @@ -1257,13 +1386,19 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmSimdReplaceLane \(op.kind) \(input(0)) lane \(op.lane)") case .wasmSimdStoreLane(let op): - w.emit("WasmSimdStoreLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)") + w.emit( + "WasmSimdStoreLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)" + ) case .wasmSimdLoadLane(let op): - w.emit("\(output()) <- WasmSimdLoadLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)") + w.emit( + "\(output()) <- WasmSimdLoadLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)" + ) case .wasmSimdLoad(let op): - w.emit("\(output()) <- WasmSimdLoad \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset)") + w.emit( + "\(output()) <- WasmSimdLoad \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset)" + ) case .wasmArrayNewFixed(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") @@ -1350,10 +1485,13 @@ public class FuzzILLifter: Lifter { case .wasmDefineArrayType(let op): let typeInput = op.elementType.requiredInputCount() == 1 ? " \(input(0))" : "" - w.emit("\(output()) <- WasmDefineArrayType \(op.elementType) mutability=\(op.mutability)\(typeInput)") + w.emit( + "\(output()) <- WasmDefineArrayType \(op.elementType) mutability=\(op.mutability)\(typeInput)" + ) case .wasmDefineStructType(let op): - let fields = op.fields.map { "\($0.type) mutability=\($0.mutability)"}.joined(separator: ", ") + let fields = op.fields.map { "\($0.type) mutability=\($0.mutability)" }.joined( + separator: ", ") let inputs = instr.inputs.map(lift).joined(separator: ", ") w.emit("\(output()) <- WasmDefineStructType(\(fields)) [\(inputs)]") @@ -1377,7 +1515,9 @@ public class FuzzILLifter: Lifter { } for instr in program.code { - if options.contains(.includeComments), let comment = program.comments.at(.instruction(instr.index)) { + if options.contains(.includeComments), + let comment = program.comments.at(.instruction(instr.index)) + { w.emitComment(comment) } @@ -1401,7 +1541,9 @@ public class FuzzILLifter: Lifter { return w.code } - private func liftCallArguments(_ args: ArraySlice, spreading spreads: [Bool] = []) -> String { + private func liftCallArguments(_ args: ArraySlice, spreading spreads: [Bool] = []) + -> String + { var arguments = [String]() for (i, v) in args.enumerated() { if spreads.count > i && spreads[i] { @@ -1413,7 +1555,9 @@ public class FuzzILLifter: Lifter { return arguments.joined(separator: ", ") } - private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) -> String { + private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) + -> String + { assert(indices.count == outputs.count) var arrayPattern = "" @@ -1429,7 +1573,9 @@ public class FuzzILLifter: Lifter { return arrayPattern } - private func liftObjectDestructPattern(properties: [String], outputs: [String], hasRestElement: Bool) -> String { + private func liftObjectDestructPattern( + properties: [String], outputs: [String], hasRestElement: Bool + ) -> String { assert(outputs.count == properties.count + (hasRestElement ? 1 : 0)) var objectPattern = "" @@ -1443,4 +1589,3 @@ public class FuzzILLifter: Lifter { return objectPattern } } - diff --git a/Sources/Fuzzilli/Lifting/JSExpressions.swift b/Sources/Fuzzilli/Lifting/JSExpressions.swift index e06d4f7fd..08a7ff800 100644 --- a/Sources/Fuzzilli/Lifting/JSExpressions.swift +++ b/Sources/Fuzzilli/Lifting/JSExpressions.swift @@ -13,9 +13,9 @@ // limitations under the License. // JavaScript expressions. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence -public let Identifier = ExpressionType(precedence: 20, characteristic: .pure) -public let Literal = ExpressionType(precedence: 20, characteristic: .pure) -public let Keyword = ExpressionType(precedence: 20, characteristic: .pure) +public let Identifier = ExpressionType(precedence: 20, characteristic: .pure) +public let Literal = ExpressionType(precedence: 20, characteristic: .pure) +public let Keyword = ExpressionType(precedence: 20, characteristic: .pure) // RegExp are objects, and so for example for the FuzzIL program // v1 <- CreateRegExp // Compare v1, v1 @@ -25,25 +25,34 @@ public let Keyword = ExpressionType(precedence: 20, // and // /a/ === /a/; // (false) // the former being the correct JavaScript equivalent. -public let RegExpLiteral = ExpressionType(precedence: 20, characteristic: .effectful) -public let CallExpression = ExpressionType(precedence: 19, associativity: .left, characteristic: .effectful) -public let MemberExpression = ExpressionType(precedence: 19, associativity: .left, characteristic: .effectful) -public let NewExpression = ExpressionType(precedence: 19, characteristic: .effectful) +public let RegExpLiteral = ExpressionType(precedence: 20, characteristic: .effectful) +public let CallExpression = ExpressionType( + precedence: 19, associativity: .left, characteristic: .effectful) +public let MemberExpression = ExpressionType( + precedence: 19, associativity: .left, characteristic: .effectful) +public let NewExpression = ExpressionType(precedence: 19, characteristic: .effectful) // Artificial, need brackets around some literals for syntactic reasons -public let NumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let NumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) // A helper expression type since negative numbers are technically unary expressions, but then they wouldn't // be inlined since unary expressions aren't generally pure. -public let NegativeNumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) -public let StringLiteral = ExpressionType(precedence: 17, characteristic: .pure) -public let TemplateLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let ObjectLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let ArrayLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let PostfixExpression = ExpressionType(precedence: 16, characteristic: .effectful) -public let UnaryExpression = ExpressionType(precedence: 15, associativity: .right, characteristic: .effectful) -public let BinaryExpression = ExpressionType(precedence: 14, associativity: .none, characteristic: .effectful) -public let TernaryExpression = ExpressionType(precedence: 4, associativity: .none, characteristic: .effectful) -public let AssignmentExpression = ExpressionType(precedence: 3, associativity: .right, characteristic: .effectful) -public let ArrowFunctionExpression = ExpressionType(precedence: 3, associativity: .right, characteristic: .effectful) -public let YieldExpression = ExpressionType(precedence: 2, associativity: .right, characteristic: .effectful) -public let SpreadExpression = ExpressionType(precedence: 2, characteristic: .effectful) -public let CommaExpression = ExpressionType(precedence: 1, associativity: .left, characteristic: .effectful) +public let NegativeNumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let StringLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let TemplateLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let ObjectLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let ArrayLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let PostfixExpression = ExpressionType(precedence: 16, characteristic: .effectful) +public let UnaryExpression = ExpressionType( + precedence: 15, associativity: .right, characteristic: .effectful) +public let BinaryExpression = ExpressionType( + precedence: 14, associativity: .none, characteristic: .effectful) +public let TernaryExpression = ExpressionType( + precedence: 4, associativity: .none, characteristic: .effectful) +public let AssignmentExpression = ExpressionType( + precedence: 3, associativity: .right, characteristic: .effectful) +public let ArrowFunctionExpression = ExpressionType( + precedence: 3, associativity: .right, characteristic: .effectful) +public let YieldExpression = ExpressionType( + precedence: 2, associativity: .right, characteristic: .effectful) +public let SpreadExpression = ExpressionType(precedence: 2, characteristic: .effectful) +public let CommaExpression = ExpressionType( + precedence: 1, associativity: .left, characteristic: .effectful) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index f65dd3cca..725796b69 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -15,479 +15,479 @@ /// This file contains the JavaScript specific implementation of the Explore operation. See ExplorationMutator.swift for an overview of this feature. struct JavaScriptExploreLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - const explore = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + const explore = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - // - // "Import" the object introspection code. This is used to find properties and methods when exploring an object. - // - \(JavaScriptRuntimeAssistedMutatorLifting.introspectionCode) + // + // "Import" the object introspection code. This is used to find properties and methods when exploring an object. + // + \(JavaScriptRuntimeAssistedMutatorLifting.introspectionCode) - // - // "Import" the Action implementation code. - // - \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) + // + // "Import" the Action implementation code. + // + \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) - // JS Action Operation groups. See e.g. exploreNumber() for examples of how they are used. - const SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT, OP_UNSIGNED_RIGHT_SHIFT]; - // Unsigned shift is not defined for bigints. - const BIGINT_SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT]; - const BITWISE_OPS = [OP_BITWISE_OR, OP_BITWISE_AND, OP_BITWISE_XOR]; - const ARITHMETIC_OPS = [OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD]; - const UNARY_OPS = [OP_INC, OP_DEC, OP_NEG, OP_BITWISE_NOT]; - const COMPARISON_OPS = [OP_COMPARE_EQUAL, OP_COMPARE_STRICT_EQUAL, OP_COMPARE_NOT_EQUAL, OP_COMPARE_STRICT_NOT_EQUAL, OP_COMPARE_GREATER_THAN, OP_COMPARE_LESS_THAN, OP_COMPARE_GREATER_THAN_OR_EQUAL, OP_COMPARE_LESS_THAN_OR_EQUAL]; - const BOOLEAN_BINARY_OPS = [OP_LOGICAL_AND, OP_LOGICAL_OR]; - const BOOLEAN_UNARY_OPS = [OP_LOGICAL_NOT]; + // JS Action Operation groups. See e.g. exploreNumber() for examples of how they are used. + const SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT, OP_UNSIGNED_RIGHT_SHIFT]; + // Unsigned shift is not defined for bigints. + const BIGINT_SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT]; + const BITWISE_OPS = [OP_BITWISE_OR, OP_BITWISE_AND, OP_BITWISE_XOR]; + const ARITHMETIC_OPS = [OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD]; + const UNARY_OPS = [OP_INC, OP_DEC, OP_NEG, OP_BITWISE_NOT]; + const COMPARISON_OPS = [OP_COMPARE_EQUAL, OP_COMPARE_STRICT_EQUAL, OP_COMPARE_NOT_EQUAL, OP_COMPARE_STRICT_NOT_EQUAL, OP_COMPARE_GREATER_THAN, OP_COMPARE_LESS_THAN, OP_COMPARE_GREATER_THAN_OR_EQUAL, OP_COMPARE_LESS_THAN_OR_EQUAL]; + const BOOLEAN_BINARY_OPS = [OP_LOGICAL_AND, OP_LOGICAL_OR]; + const BOOLEAN_UNARY_OPS = [OP_LOGICAL_NOT]; - // - // Global constants. - // - // Property names to use when defining new properties. Should be kept in sync with the equivalent set in JavaScriptEnvironment.swift - const customPropertyNames = [\(JavaScriptEnvironment.CustomPropertyNames.map({ "\"\($0)\"" }).joined(separator: ", "))]; + // + // Global constants. + // + // Property names to use when defining new properties. Should be kept in sync with the equivalent set in JavaScriptEnvironment.swift + const customPropertyNames = [\(JavaScriptEnvironment.CustomPropertyNames.map({ "\"\($0)\"" }).joined(separator: ", "))]; - // Maximum number of parameters for function/method calls. Everything above this is consiered an invalid .length property of the function. - const MAX_PARAMETERS = 10; + // Maximum number of parameters for function/method calls. Everything above this is consiered an invalid .length property of the function. + const MAX_PARAMETERS = 10; - // Well known integer/number values to use when generating random values. - const WELL_KNOWN_INTEGERS = filter([\(JavaScriptEnvironment.InterestingIntegers.map(String.init).joined(separator: ", "))], isInteger); - const WELL_KNOWN_NUMBERS = concat(WELL_KNOWN_INTEGERS, [-1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6]); - const WELL_KNOWN_BIGINTS = [\(JavaScriptEnvironment.InterestingIntegers.map({ "\($0)n" }).joined(separator: ", "))]; + // Well known integer/number values to use when generating random values. + const WELL_KNOWN_INTEGERS = filter([\(JavaScriptEnvironment.InterestingIntegers.map(String.init).joined(separator: ", "))], isInteger); + const WELL_KNOWN_NUMBERS = concat(WELL_KNOWN_INTEGERS, [-1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6]); + const WELL_KNOWN_BIGINTS = [\(JavaScriptEnvironment.InterestingIntegers.map({ "\($0)n" }).joined(separator: ", "))]; - // - // Global state. - // + // + // Global state. + // - // The concrete argument values that will be used when executing the Action for the current exploration operation. - let exploreArguments; + // The concrete argument values that will be used when executing the Action for the current exploration operation. + let exploreArguments; - // The input containing the value being explored. This should always be the first input to every Action created during exploration. - let exploredValueInput; + // The input containing the value being explored. This should always be the first input to every Action created during exploration. + let exploredValueInput; - // Whether exploration is currently happening. This is required to detect recursive exploration, where for example a callback - // triggered during property enumeration triggers further exploration calls. See explore(). - let currentlyExploring = false; + // Whether exploration is currently happening. This is required to detect recursive exploration, where for example a callback + // triggered during property enumeration triggers further exploration calls. See explore(). + let currentlyExploring = false; - // - // Error and result reporting. - // - // Results (indexed by their ID) will be stored in here. - const results = { __proto__: null }; + // + // Error and result reporting. + // + // Results (indexed by their ID) will be stored in here. + const results = { __proto__: null }; - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ERROR: ' + msg); - } - - function recordFailure(id) { - // Delete the property if it already exists (from recordAction). - delete results[id]; - defineProperty(results, id, {__proto__: null, value: NO_ACTION}); - - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_FAILURE: ' + id); - } - - function recordAction(id, action) { - if (hasOwnProperty(results, id)) { - throw "Duplicate action for " + id; + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ERROR: ' + msg); } - if (action === NO_ACTION) { - // This is equivalent to a failure. - return recordFailure(id); + function recordFailure(id) { + // Delete the property if it already exists (from recordAction). + delete results[id]; + defineProperty(results, id, {__proto__: null, value: NO_ACTION}); + + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_FAILURE: ' + id); } - action.id = id; - - // These are configurable as they may need to be overwritten (by recordFailure) in the future. - defineProperty(results, id, {__proto__: null, value: action, configurable: true}); - - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ACTION: ' + stringify(action)); - } - - function hasActionFor(id) { - return hasOwnProperty(results, id); - } - - function getActionFor(id) { - return results[id]; - } - - // - // Access to random inputs. - // - // These functions prefer to take an existing variable from the arguments to the Explore operations if it satistifes the specified criteria. Otherwise, they generate a new random value. - // Testing whether an argument satisfies some criteria (e.g. be a value in a certain range) may trigger type conversions. This is expected as it may lead to interesting values being used. - // These are grouped into a namespace object to make it more clear that they return an Input object (from one of the above constructors), rather than a value. - // - let Inputs = { - randomArgument() { - return new ArgumentInput(randomIntBelow(exploreArguments.length)); - }, - - randomArguments(n) { - let args = EmptyArray(); - for (let i = 0; i < n; i++) { - push(args, new ArgumentInput(randomIntBelow(exploreArguments.length))); + function recordAction(id, action) { + if (hasOwnProperty(results, id)) { + throw "Duplicate action for " + id; } - return args; - }, - randomArgumentForReplacing(propertyName, obj) { - let curValue = tryGetProperty(propertyName, obj); - if (isUndefined(curValue)) { - return Inputs.randomArgument(); + if (action === NO_ACTION) { + // This is equivalent to a failure. + return recordFailure(id); } - function isCompatible(arg) { - let sameType = typeof curValue === typeof arg; - if (sameType && isObject(curValue)) { - sameType = arg instanceof curValue.constructor; - } - return sameType; - } + action.id = id; - let idx = findIndex(exploreArguments, wrapInTryCatch(isCompatible)); - if (idx != -1) return new ArgumentInput(idx); - return Inputs.randomArgument(); - }, - - randomInt() { - let idx = findIndex(exploreArguments, isInteger); - if (idx != -1) return new ArgumentInput(idx); - return new IntInput(randomElement(WELL_KNOWN_INTEGERS)); - }, - - randomNumber() { - let idx = findIndex(exploreArguments, isNumber); - if (idx != -1) return new ArgumentInput(idx); - return new FloatInput(randomElement(WELL_KNOWN_NUMBERS)); - }, - - randomBigint() { - let idx = findIndex(exploreArguments, isBigint); - if (idx != -1) return new ArgumentInput(idx); - return new BigintInput(randomElement(WELL_KNOWN_BIGINTS)); - }, - - randomIntBetween(start, end) { - if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => NumberIsInteger(e) && (e >= start) && (e < end))); - if (idx != -1) return new ArgumentInput(idx); - return new IntInput(randomIntBetween(start, end)); - }, - - randomBigintBetween(start, end) { - if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; - if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular integers"; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= start) && (e < end))); - if (idx != -1) return new ArgumentInput(idx); - return new BigintInput(randomBigintBetween(start, end)); - }, - - randomNumberCloseTo(v) { - if (!isFinite(v)) throw "Argument to randomNumberCloseTo is not a finite number: " + v; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10) && (e <= v + 10))); - if (idx != -1) return new ArgumentInput(idx); - let step = randomIntBetween(-10, 10); - let value = v + step; - if (isInteger(value)) { - return new IntInput(value); - } else { - return new FloatInput(v + step); - } - }, - - randomBigintCloseTo(v) { - if (!isBigint(v)) throw "Argument to randomBigintCloseTo is not a bigint: " + v; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10n) && (e <= v + 10n))); - if (idx != -1) return new ArgumentInput(idx); - let step = randomBigintBetween(-10n, 10n); - let value = v + step; - return new BigintInput(value); - } - } + // These are configurable as they may need to be overwritten (by recordFailure) in the future. + defineProperty(results, id, {__proto__: null, value: action, configurable: true}); - // Heuristic to determine when a function should be invoked as a constructor. Used by the object and function exploration code. - function shouldTreatAsConstructor(f) { - let name = tryGetProperty('name', f); - - // If the function has no name (or a non-string name), it's probably a regular function (or something like an arrow function). - if (!isString(name) || name.length < 1) { - return probability(0.1); + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ACTION: ' + stringify(action)); } - // If the name is something like `f42`, it's probably a function defined by Fuzzilli. These can typicall be used as function or constructor, but prefer to call them as regular functions. - if (name[0] === 'f' && !isNaN(parseInteger(stringSlice(name, 1)))) { - return probability(0.2); + function hasActionFor(id) { + return hasOwnProperty(results, id); } - // Otherwise, the basic heuristic is that functions that start with an uppercase letter (e.g. Object, Uint8Array, etc.) are probably constructors (but not always, e.g. BigInt). - // This is also compatible with Fuzzilli's lifting of classes, as they will look something like this: `class V3 { ...`. - if (name[0] === toUpperCase(name[0])) { - return probability(0.9); - } else { - return probability(0.1); - } - } - - // - // Explore implementation for different basic types. - // - // These all return an Action object or the special NO_ACTION value (null). - // - function exploreObject(o) { - if (o === null) { - return exploreNullish(o); + function getActionFor(id) { + return results[id]; } - // TODO: Add special handling for ArrayBuffers: most of the time, wrap these into a Uint8Array to be able to modify them. - // TODO: Sometimes iterate over iterable objects (e.g. Arrays)? + // + // Access to random inputs. + // + // These functions prefer to take an existing variable from the arguments to the Explore operations if it satistifes the specified criteria. Otherwise, they generate a new random value. + // Testing whether an argument satisfies some criteria (e.g. be a value in a certain range) may trigger type conversions. This is expected as it may lead to interesting values being used. + // These are grouped into a namespace object to make it more clear that they return an Input object (from one of the above constructors), rather than a value. + // + let Inputs = { + randomArgument() { + return new ArgumentInput(randomIntBelow(exploreArguments.length)); + }, + + randomArguments(n) { + let args = EmptyArray(); + for (let i = 0; i < n; i++) { + push(args, new ArgumentInput(randomIntBelow(exploreArguments.length))); + } + return args; + }, - // Determine a random property, which can generally either be a method, an element, or a "regular" property. - let propertyName = randomPropertyOf(o); + randomArgumentForReplacing(propertyName, obj) { + let curValue = tryGetProperty(propertyName, obj); + if (isUndefined(curValue)) { + return Inputs.randomArgument(); + } - // Determine the appropriate action to perform given the selected property. - // If the property lookup failed (for whatever reason), we always define a new property. - if (propertyName === null) { - let propertyNameInput = new StringInput(randomElement(customPropertyNames)); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); - } else if (isInteger(propertyName)) { - let propertyNameInput = new IntInput(propertyName); - if (probability(0.5)) { - return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); - } else { - let newValue = Inputs.randomArgumentForReplacing(propertyName, o); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); - } - } else if (isString(propertyName)) { - let propertyNameInput = new StringInput(propertyName); - let propertyValue = tryGetProperty(propertyName, o); - if (isFunction(propertyValue)) { - // Perform a method call/construct. - let numParameters = tryGetProperty('length', propertyValue); - if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) return NO_ACTION; - let inputs = EmptyArray(); - push(inputs, exploredValueInput); - push(inputs, propertyNameInput); - for (let i = 0; i < numParameters; i++) { - push(inputs, Inputs.randomArgument()); + function isCompatible(arg) { + let sameType = typeof curValue === typeof arg; + if (sameType && isObject(curValue)) { + sameType = arg instanceof curValue.constructor; + } + return sameType; } - if (shouldTreatAsConstructor(propertyValue)) { - return new GuardedAction(OP_CONSTRUCT_METHOD, inputs); + + let idx = findIndex(exploreArguments, wrapInTryCatch(isCompatible)); + if (idx != -1) return new ArgumentInput(idx); + return Inputs.randomArgument(); + }, + + randomInt() { + let idx = findIndex(exploreArguments, isInteger); + if (idx != -1) return new ArgumentInput(idx); + return new IntInput(randomElement(WELL_KNOWN_INTEGERS)); + }, + + randomNumber() { + let idx = findIndex(exploreArguments, isNumber); + if (idx != -1) return new ArgumentInput(idx); + return new FloatInput(randomElement(WELL_KNOWN_NUMBERS)); + }, + + randomBigint() { + let idx = findIndex(exploreArguments, isBigint); + if (idx != -1) return new ArgumentInput(idx); + return new BigintInput(randomElement(WELL_KNOWN_BIGINTS)); + }, + + randomIntBetween(start, end) { + if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => NumberIsInteger(e) && (e >= start) && (e < end))); + if (idx != -1) return new ArgumentInput(idx); + return new IntInput(randomIntBetween(start, end)); + }, + + randomBigintBetween(start, end) { + if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; + if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular integers"; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= start) && (e < end))); + if (idx != -1) return new ArgumentInput(idx); + return new BigintInput(randomBigintBetween(start, end)); + }, + + randomNumberCloseTo(v) { + if (!isFinite(v)) throw "Argument to randomNumberCloseTo is not a finite number: " + v; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10) && (e <= v + 10))); + if (idx != -1) return new ArgumentInput(idx); + let step = randomIntBetween(-10, 10); + let value = v + step; + if (isInteger(value)) { + return new IntInput(value); } else { - return new GuardedAction(OP_CALL_METHOD, inputs); + return new FloatInput(v + step); } + }, + + randomBigintCloseTo(v) { + if (!isBigint(v)) throw "Argument to randomBigintCloseTo is not a bigint: " + v; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10n) && (e <= v + 10n))); + if (idx != -1) return new ArgumentInput(idx); + let step = randomBigintBetween(-10n, 10n); + let value = v + step; + return new BigintInput(value); + } + } + + // Heuristic to determine when a function should be invoked as a constructor. Used by the object and function exploration code. + function shouldTreatAsConstructor(f) { + let name = tryGetProperty('name', f); + + // If the function has no name (or a non-string name), it's probably a regular function (or something like an arrow function). + if (!isString(name) || name.length < 1) { + return probability(0.1); + } + + // If the name is something like `f42`, it's probably a function defined by Fuzzilli. These can typicall be used as function or constructor, but prefer to call them as regular functions. + if (name[0] === 'f' && !isNaN(parseInteger(stringSlice(name, 1)))) { + return probability(0.2); + } + + // Otherwise, the basic heuristic is that functions that start with an uppercase letter (e.g. Object, Uint8Array, etc.) are probably constructors (but not always, e.g. BigInt). + // This is also compatible with Fuzzilli's lifting of classes, as they will look something like this: `class V3 { ...`. + if (name[0] === toUpperCase(name[0])) { + return probability(0.9); } else { - // Perform a property access. - // Besides getting and setting the property, we also sometimes define a new property instead. - if (probability(1/3)) { - propertyNameInput = new StringInput(randomElement(customPropertyNames)); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); - } else if (probability(0.5)) { + return probability(0.1); + } + } + + // + // Explore implementation for different basic types. + // + // These all return an Action object or the special NO_ACTION value (null). + // + function exploreObject(o) { + if (o === null) { + return exploreNullish(o); + } + + // TODO: Add special handling for ArrayBuffers: most of the time, wrap these into a Uint8Array to be able to modify them. + // TODO: Sometimes iterate over iterable objects (e.g. Arrays)? + + // Determine a random property, which can generally either be a method, an element, or a "regular" property. + let propertyName = randomPropertyOf(o); + + // Determine the appropriate action to perform given the selected property. + // If the property lookup failed (for whatever reason), we always define a new property. + if (propertyName === null) { + let propertyNameInput = new StringInput(randomElement(customPropertyNames)); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); + } else if (isInteger(propertyName)) { + let propertyNameInput = new IntInput(propertyName); + if (probability(0.5)) { return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); } else { let newValue = Inputs.randomArgumentForReplacing(propertyName, o); return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); } + } else if (isString(propertyName)) { + let propertyNameInput = new StringInput(propertyName); + let propertyValue = tryGetProperty(propertyName, o); + if (isFunction(propertyValue)) { + // Perform a method call/construct. + let numParameters = tryGetProperty('length', propertyValue); + if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) return NO_ACTION; + let inputs = EmptyArray(); + push(inputs, exploredValueInput); + push(inputs, propertyNameInput); + for (let i = 0; i < numParameters; i++) { + push(inputs, Inputs.randomArgument()); + } + if (shouldTreatAsConstructor(propertyValue)) { + return new GuardedAction(OP_CONSTRUCT_METHOD, inputs); + } else { + return new GuardedAction(OP_CALL_METHOD, inputs); + } + } else { + // Perform a property access. + // Besides getting and setting the property, we also sometimes define a new property instead. + if (probability(1/3)) { + propertyNameInput = new StringInput(randomElement(customPropertyNames)); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); + } else if (probability(0.5)) { + return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); + } else { + let newValue = Inputs.randomArgumentForReplacing(propertyName, o); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); + } + } + } else { + throw "Got unexpected property name from Inputs.randomPropertyOf(): " + propertyName; } - } else { - throw "Got unexpected property name from Inputs.randomPropertyOf(): " + propertyName; } - } - function exploreFunction(f) { - // Sometimes treat functions as objects. - // This will cause interesting properties like 'arguments' or 'prototype' to be accessed, methods like 'apply' or 'bind' to be called, and methods on builtin constructors like 'Array', and 'Object' to be used. - if (probability(0.5)) { - return exploreObject(f); - } + function exploreFunction(f) { + // Sometimes treat functions as objects. + // This will cause interesting properties like 'arguments' or 'prototype' to be accessed, methods like 'apply' or 'bind' to be called, and methods on builtin constructors like 'Array', and 'Object' to be used. + if (probability(0.5)) { + return exploreObject(f); + } - // Otherwise, call or construct the function/constructor. - let numParameters = tryGetProperty('length', f); - if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) { - numParameters = 0; - } - let inputs = EmptyArray(); - push(inputs, exploredValueInput); - for (let i = 0; i < numParameters; i++) { - push(inputs, Inputs.randomArgument()); - } - let operation = shouldTreatAsConstructor(f) ? OP_CONSTRUCT : OP_CALL_FUNCTION; - return new GuardedAction(operation, inputs); - } - - function exploreString(s) { - // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. - // TODO: sometimes access a character of the string or iterate over it? - if (probability(0.1) && isShortString(s)) { - return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); - } else { - return exploreObject(new String(s)); + // Otherwise, call or construct the function/constructor. + let numParameters = tryGetProperty('length', f); + if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) { + numParameters = 0; + } + let inputs = EmptyArray(); + push(inputs, exploredValueInput); + for (let i = 0; i < numParameters; i++) { + push(inputs, Inputs.randomArgument()); + } + let operation = shouldTreatAsConstructor(f) ? OP_CONSTRUCT : OP_CALL_FUNCTION; + return new GuardedAction(operation, inputs); } - } - - const ALL_NUMBER_OPERATIONS = concat(SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); - const ALL_NUMBER_OPERATIONS_AND_COMPARISONS = concat(ALL_NUMBER_OPERATIONS, COMPARISON_OPS); - function exploreNumber(n) { - // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. - let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(COMPARISON_OPS, operation)) { - if (isNaN(n)) { - // In that case, regular comparisons don't make sense, so just test for isNaN instead. - action.operation = OP_TEST_IS_NAN; - } else if (!isFinite(n)) { - // Similar to the NaN case, just test for isFinite here. - action.operation = OP_TEST_IS_FINITE; + + function exploreString(s) { + // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. + // TODO: sometimes access a character of the string or iterate over it? + if (probability(0.1) && isShortString(s)) { + return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); } else { - push(action.inputs, Inputs.randomNumberCloseTo(n)); + return exploreObject(new String(s)); } - } else if (includes(SHIFT_OPS, operation)) { - push(action.inputs, Inputs.randomIntBetween(1, 32)); - } else if (includes(BITWISE_OPS, operation)) { - push(action.inputs, Inputs.randomInt()); - } else if (includes(ARITHMETIC_OPS, operation)) { - if (isInteger(n)) { + } + + const ALL_NUMBER_OPERATIONS = concat(SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); + const ALL_NUMBER_OPERATIONS_AND_COMPARISONS = concat(ALL_NUMBER_OPERATIONS, COMPARISON_OPS); + function exploreNumber(n) { + // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. + let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(COMPARISON_OPS, operation)) { + if (isNaN(n)) { + // In that case, regular comparisons don't make sense, so just test for isNaN instead. + action.operation = OP_TEST_IS_NAN; + } else if (!isFinite(n)) { + // Similar to the NaN case, just test for isFinite here. + action.operation = OP_TEST_IS_FINITE; + } else { + push(action.inputs, Inputs.randomNumberCloseTo(n)); + } + } else if (includes(SHIFT_OPS, operation)) { + push(action.inputs, Inputs.randomIntBetween(1, 32)); + } else if (includes(BITWISE_OPS, operation)) { push(action.inputs, Inputs.randomInt()); - } else { - push(action.inputs, Inputs.randomNumber()); + } else if (includes(ARITHMETIC_OPS, operation)) { + if (isInteger(n)) { + push(action.inputs, Inputs.randomInt()); + } else { + push(action.inputs, Inputs.randomNumber()); + } } + return action; } - return action; - } - - const ALL_BIGINT_OPERATIONS = concat(BIGINT_SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); - const ALL_BIGINT_OPERATIONS_AND_COMPARISONS = concat(ALL_BIGINT_OPERATIONS, COMPARISON_OPS); - function exploreBigint(b) { - // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. - let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(COMPARISON_OPS, operation)) { - push(action.inputs, Inputs.randomBigintCloseTo(b)); - } else if (includes(BIGINT_SHIFT_OPS, operation)) { - push(action.inputs, Inputs.randomBigintBetween(1n, 128n)); - } else if (includes(BITWISE_OPS, operation) || includes(ARITHMETIC_OPS, operation)) { - push(action.inputs, Inputs.randomBigint()); - } - return action; - } - - function exploreSymbol(s) { - // Lookup or insert the symbol into the global symbol registry. This will also allow static typing of the output. - return new Action(OP_SYMBOL_REGISTRATION, [exploredValueInput]); - } - - const ALL_BOOLEAN_OPERATIONS = concat(BOOLEAN_BINARY_OPS, BOOLEAN_UNARY_OPS); - function exploreBoolean(b) { - let operation = randomElement(ALL_BOOLEAN_OPERATIONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(BOOLEAN_BINARY_OPS, operation)) { - // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. - push(action.inputs, Inputs.randomArgument()); + + const ALL_BIGINT_OPERATIONS = concat(BIGINT_SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); + const ALL_BIGINT_OPERATIONS_AND_COMPARISONS = concat(ALL_BIGINT_OPERATIONS, COMPARISON_OPS); + function exploreBigint(b) { + // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. + let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(COMPARISON_OPS, operation)) { + push(action.inputs, Inputs.randomBigintCloseTo(b)); + } else if (includes(BIGINT_SHIFT_OPS, operation)) { + push(action.inputs, Inputs.randomBigintBetween(1n, 128n)); + } else if (includes(BITWISE_OPS, operation) || includes(ARITHMETIC_OPS, operation)) { + push(action.inputs, Inputs.randomBigint()); + } + return action; } - return action; - } - - function exploreNullish(v) { - // Best thing we can do with nullish values is a NullCoalescing (??) operation. - return new Action(OP_NULL_COALESCE, [exploredValueInput, Inputs.randomArgument()]) - } - - // Explores the given value and returns an action to perform on it. - function exploreValue(id, v) { - if (isObject(v)) { - return exploreObject(v); - } else if (isFunction(v)) { - return exploreFunction(v); - } else if (isString(v)) { - return exploreString(v); - } else if (isNumber(v)) { - return exploreNumber(v); - } else if (isBigint(v)) { - return exploreBigint(v); - } else if (isSymbol(v)) { - return exploreSymbol(v); - } else if (isBoolean(v)) { - return exploreBoolean(v); - } else if (isUndefined(v)) { - return exploreNullish(v); - } else { - throw "Unexpected value type: " + typeof v; + + function exploreSymbol(s) { + // Lookup or insert the symbol into the global symbol registry. This will also allow static typing of the output. + return new Action(OP_SYMBOL_REGISTRATION, [exploredValueInput]); } - } - - // - // Exploration entrypoint. - // - function explore(id, v, currentThis, args, rngSeed) { - rng.reseed(rngSeed); - - // The given arguments may be used as inputs for the action. - if (isUndefined(args) || args.length < 1) throw "Exploration requires at least one additional argument"; - - // We may get here recursively for example if a Proxy is being explored which triggers further explore calls during e.g. property enumeration. - // Probably the best way to deal with these cases is to just bail out from recursive explorations. - if (currentlyExploring) return; - currentlyExploring = true; - - // Set the global state for this explore operation. - exploreArguments = args; - exploredValueInput = new SpecialInput("exploredValue"); - - // Check if we already have a result for this id, and if so repeat the same action again. Otherwise, explore. - let action; - if (hasActionFor(id)) { - action = getActionFor(id); - } else { - action = exploreValue(id, v); - recordAction(id, action); + + const ALL_BOOLEAN_OPERATIONS = concat(BOOLEAN_BINARY_OPS, BOOLEAN_UNARY_OPS); + function exploreBoolean(b) { + let operation = randomElement(ALL_BOOLEAN_OPERATIONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(BOOLEAN_BINARY_OPS, operation)) { + // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. + push(action.inputs, Inputs.randomArgument()); + } + return action; } - // Now perform the selected action. - let context = { arguments: args, specialValues: { "exploredValue": v }, currentThis: currentThis }; - let success = execute(action, context); + function exploreNullish(v) { + // Best thing we can do with nullish values is a NullCoalescing (??) operation. + return new Action(OP_NULL_COALESCE, [exploredValueInput, Inputs.randomArgument()]) + } - // If the action failed, mark this explore operation as failing (which will set the action to NO_ACTION) so it won't be retried again. - if (!success) { - recordFailure(id); + // Explores the given value and returns an action to perform on it. + function exploreValue(id, v) { + if (isObject(v)) { + return exploreObject(v); + } else if (isFunction(v)) { + return exploreFunction(v); + } else if (isString(v)) { + return exploreString(v); + } else if (isNumber(v)) { + return exploreNumber(v); + } else if (isBigint(v)) { + return exploreBigint(v); + } else if (isSymbol(v)) { + return exploreSymbol(v); + } else if (isBoolean(v)) { + return exploreBoolean(v); + } else if (isUndefined(v)) { + return exploreNullish(v); + } else { + throw "Unexpected value type: " + typeof v; + } } - currentlyExploring = false; - } + // + // Exploration entrypoint. + // + function explore(id, v, currentThis, args, rngSeed) { + rng.reseed(rngSeed); + + // The given arguments may be used as inputs for the action. + if (isUndefined(args) || args.length < 1) throw "Exploration requires at least one additional argument"; + + // We may get here recursively for example if a Proxy is being explored which triggers further explore calls during e.g. property enumeration. + // Probably the best way to deal with these cases is to just bail out from recursive explorations. + if (currentlyExploring) return; + currentlyExploring = true; + + // Set the global state for this explore operation. + exploreArguments = args; + exploredValueInput = new SpecialInput("exploredValue"); - function exploreWithErrorHandling(id, v, thisValue, args, rngSeed) { - try { - explore(id, v, thisValue, args, rngSeed); - } catch (e) { - let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); - if (isNumber(line)) { - reportError("In line " + line + ": " + e); + // Check if we already have a result for this id, and if so repeat the same action again. Otherwise, explore. + let action; + if (hasActionFor(id)) { + action = getActionFor(id); } else { - reportError(e); + action = exploreValue(id, v); + recordAction(id, action); + } + + // Now perform the selected action. + let context = { arguments: args, specialValues: { "exploredValue": v }, currentThis: currentThis }; + let success = execute(action, context); + + // If the action failed, mark this explore operation as failing (which will set the action to NO_ACTION) so it won't be retried again. + if (!success) { + recordFailure(id); + } + + currentlyExploring = false; + } + + function exploreWithErrorHandling(id, v, thisValue, args, rngSeed) { + try { + explore(id, v, thisValue, args, rngSeed); + } catch (e) { + let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); + if (isNumber(line)) { + reportError("In line " + line + ": " + e); + } else { + reportError(e); + } } } - } - return exploreWithErrorHandling; - })(); + return exploreWithErrorHandling; + })(); - """ + """ static let exploreFunc = "explore" } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift index e267b1433..9d2c12360 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift @@ -15,115 +15,115 @@ /// This file contains the JavaScript specific implementation of the Fixup operation. See FixupMutator.swift for an overview of this feature. struct JavaScriptFixupLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - - const fixup = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - - - // - // "Import" the Action implementation code. - // - \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) - - - // - // Error and result reporting. - // - // The actions to perform (indexed by their ID) will be stored in here. - // TODO: here and in ExploreLifting, should this be a Map instead? - const actions = { __proto__: null }; - // We remember which actions have failed in the past, so we only report failures once. - const failures = new SetConstructor(); - - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'FIXUP_ERROR: ' + msg); - } - - function recordFailure(id) { - setAdd(failures, id); - fuzzilli('FUZZILLI_PRINT', 'FIXUP_FAILURE: ' + id); - } - - function recordAction(id, action) { - if (action.id !== id) throw "Inconsistent action for id " + id; - if (hasOwnProperty(actions, id)) throw "Duplicate action for " + id; - - // These are configurable as they may need to be overwritten (by recordFailure) in the future. - defineProperty(actions, id, {__proto__: null, value: action, configurable: true}); - - fuzzilli('FUZZILLI_PRINT', 'FIXUP_ACTION: ' + stringify(action)); - } - - function hasActionFor(id) { - return hasOwnProperty(actions, id); - } - - function getActionFor(id) { - return actions[id]; - } - - function hasPreviouslyFailed(id) { - return setHas(failures, id); - } - - // - // Fixup function. - // - function fixup(id, originalAction, args, currentThis) { - // See if this is the first time that we're executing this action. If it is, then now is the (only) timewhen we can modify the action. - let action; - if (hasActionFor(id)) { - action = getActionFor(id); - } else { - // TODO: this is where we could change the action. - // If changing actions, we should try to not change the type of inputs though. For example, we probably should not - // turn a computed property load (where the property name is an argument input) into a "regular" property load - // (where the property name is a string input). - action = originalAction; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + + const fixup = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + + + // + // "Import" the Action implementation code. + // + \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) + + + // + // Error and result reporting. + // + // The actions to perform (indexed by their ID) will be stored in here. + // TODO: here and in ExploreLifting, should this be a Map instead? + const actions = { __proto__: null }; + // We remember which actions have failed in the past, so we only report failures once. + const failures = new SetConstructor(); + + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'FIXUP_ERROR: ' + msg); + } + + function recordFailure(id) { + setAdd(failures, id); + fuzzilli('FUZZILLI_PRINT', 'FIXUP_FAILURE: ' + id); + } + + function recordAction(id, action) { + if (action.id !== id) throw "Inconsistent action for id " + id; + if (hasOwnProperty(actions, id)) throw "Duplicate action for " + id; + + // These are configurable as they may need to be overwritten (by recordFailure) in the future. + defineProperty(actions, id, {__proto__: null, value: action, configurable: true}); + + fuzzilli('FUZZILLI_PRINT', 'FIXUP_ACTION: ' + stringify(action)); } - // Now perform the selected action. - let context = { arguments: args, specialValues: {}, currentThis: currentThis, output: undefined }; - let success = execute(action, context); + function hasActionFor(id) { + return hasOwnProperty(actions, id); + } - // If the action failed and isn't guarded (either because it wasn't in the first place or because we've previously removed the guard), then record a failure. - // This will signal to Fuzzilli that the action either needs a guard or should be removed. - // As we may execute this action again, we remember which actions have failed in the past and only report the first failure. - if (!success && !hasPreviouslyFailed(id)) { - recordFailure(id); + function getActionFor(id) { + return actions[id]; } - // If this was the first time the action was executed, report the (possibly modified) action. - // This has to happen after executing the action as that may remove unecessary guards. - if (!hasActionFor(id)) { - recordAction(id, action); + function hasPreviouslyFailed(id) { + return setHas(failures, id); } - // Return the action's output value as it may be used by subsequent code. - return context.output; - } - - function fixupWithErrorHandling(id, originalAction, args, currentThis) { - try { - return fixup(id, originalAction, args, currentThis); - } catch (e) { - let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); - if (isNumber(line)) { - reportError("In line " + line + ": " + e); + // + // Fixup function. + // + function fixup(id, originalAction, args, currentThis) { + // See if this is the first time that we're executing this action. If it is, then now is the (only) timewhen we can modify the action. + let action; + if (hasActionFor(id)) { + action = getActionFor(id); } else { - reportError(e); + // TODO: this is where we could change the action. + // If changing actions, we should try to not change the type of inputs though. For example, we probably should not + // turn a computed property load (where the property name is an argument input) into a "regular" property load + // (where the property name is a string input). + action = originalAction; + } + + // Now perform the selected action. + let context = { arguments: args, specialValues: {}, currentThis: currentThis, output: undefined }; + let success = execute(action, context); + + // If the action failed and isn't guarded (either because it wasn't in the first place or because we've previously removed the guard), then record a failure. + // This will signal to Fuzzilli that the action either needs a guard or should be removed. + // As we may execute this action again, we remember which actions have failed in the past and only report the first failure. + if (!success && !hasPreviouslyFailed(id)) { + recordFailure(id); + } + + // If this was the first time the action was executed, report the (possibly modified) action. + // This has to happen after executing the action as that may remove unecessary guards. + if (!hasActionFor(id)) { + recordAction(id, action); + } + + // Return the action's output value as it may be used by subsequent code. + return context.output; + } + + function fixupWithErrorHandling(id, originalAction, args, currentThis) { + try { + return fixup(id, originalAction, args, currentThis); + } catch (e) { + let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); + if (isNumber(line)) { + reportError("In line " + line + ": " + e); + } else { + reportError(e); + } } } - } - return fixupWithErrorHandling; - })(); - """ + return fixupWithErrorHandling; + })(); + """ static let fixupFunc = "fixup" } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index f38081d9f..8f12d3f0e 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -75,11 +75,13 @@ public class JavaScriptLifter: Lifter { } private var functionLiftingStack = Stack() - public init(prefix: String = "", - suffix: String = "", - ecmaVersion: ECMAScriptVersion, - environment: JavaScriptEnvironment, - alwaysEmitVariables: Bool = false) { + public init( + prefix: String = "", + suffix: String = "", + ecmaVersion: ECMAScriptVersion, + environment: JavaScriptEnvironment, + alwaysEmitVariables: Bool = false + ) { self.prefix = prefix self.suffix = suffix self.version = ecmaVersion @@ -88,11 +90,15 @@ public class JavaScriptLifter: Lifter { self.alwaysEmitVariables = alwaysEmitVariables } - func isUsedInBlock(variable: Variable, blockStart: Int, blockEnd: Int, analyzer: DefUseAnalyzer) -> Bool { + func isUsedInBlock(variable: Variable, blockStart: Int, blockEnd: Int, analyzer: DefUseAnalyzer) + -> Bool + { // Check if any use of 'variable' is inside [blockStart, blockEnd] // Note: The variable is defined at blockStart, so we only care about uses strictly after that. // And strictly before or at blockEnd (the EndInstruction itself can use the variable). - return analyzer.uses(of: variable).contains { $0.index > blockStart && $0.index <= blockEnd } + return analyzer.uses(of: variable).contains { + $0.index > blockStart && $0.index <= blockEnd + } } public func lift(_ program: Program, withOptions options: LiftingOptions) -> String { @@ -110,7 +116,9 @@ public class JavaScriptLifter: Lifter { var wasmInstructions = Code() // Map block start index to end index. - let blockEndIndices = program.code.reduce(into: (indices: [Int: Int](), stack: Stack())) { context, instr in + let blockEndIndices = program.code.reduce( + into: (indices: [Int: Int](), stack: Stack()) + ) { context, instr in if instr.isBlockEnd { let start = context.stack.pop() context.indices[start] = instr.index @@ -134,7 +142,11 @@ public class JavaScriptLifter: Lifter { typer = JSTyper(for: environment) } - var w = JavaScriptWriter(analyzer: analyzer, version: version, stripComments: !options.contains(.includeComments), includeLineNumbers: options.contains(.includeLineNumbers), alwaysEmitVariables: alwaysEmitVariables) + var w = JavaScriptWriter( + analyzer: analyzer, version: version, + stripComments: !options.contains(.includeComments), + includeLineNumbers: options.contains(.includeLineNumbers), + alwaysEmitVariables: alwaysEmitVariables) var wasmCodeStarts: Int? = nil var wasmTypeGroupStarts: Int? = nil @@ -176,7 +188,9 @@ public class JavaScriptLifter: Lifter { } for instr in program.code { - if options.contains(.includeComments), let comment = program.comments.at(.instruction(instr.index)) { + if options.contains(.includeComments), + let comment = program.comments.at(.instruction(instr.index)) + { w.emitComment(comment) } @@ -240,7 +254,9 @@ public class JavaScriptLifter: Lifter { // We need to declare all outputs of the guarded operation before the try-catch so that they are // visible to subsequent code. - assert(instr.numInnerOutputs == 0, "Inner outputs are not currently supported in guarded operations") + assert( + instr.numInnerOutputs == 0, + "Inner outputs are not currently supported in guarded operations") let neededOutputs = instr.allOutputs.filter({ analyzer.numUses(of: $0) > 0 }) if !neededOutputs.isEmpty { let VARS = w.declareAll(neededOutputs).joined(separator: ", ") @@ -260,9 +276,10 @@ public class JavaScriptLifter: Lifter { // We also have some lightweight checking logic to ensure that the input expressions are retrieved in the correct order. // This does not guarantee that they will also _evaluate_ in that order at runtime, but it's probably a decent approximation. guard let inputs = w.retrieve(expressionsFor: instr.inputs) else { - fatalError("Missing one or more expressions for inputs \(instr.inputs) of \(instr).\n" + - "Program is \(FuzzILLifter().lift(program, withOptions: .includeComments))\n" + - "Dying now.") + fatalError( + "Missing one or more expressions for inputs \(instr.inputs) of \(instr).\n" + + "Program is \(FuzzILLifter().lift(program, withOptions: .includeComments))\n" + + "Dying now.") } var nextExpressionToFetch = 0 func input(_ i: Int) -> Expression { @@ -302,7 +319,7 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .loadString(let op): - let escaped = op.value.replacingOccurrences(of: "\"", with:"\\\"") + let escaped = op.value.replacingOccurrences(of: "\"", with: "\\\"") w.assign(StringLiteral.new("\"\(escaped)\""), to: instr.output) case .loadRegExp(let op): @@ -355,20 +372,20 @@ public class JavaScriptLifter: Lifter { w.declare(instr.output, as: op.variableName) case .createNamedDisposableVariable(let op): - w.emit("using \(op.variableName) = \(input(0));"); + w.emit("using \(op.variableName) = \(input(0));") w.declare(instr.output, as: op.variableName) case .createNamedAsyncDisposableVariable(let op): - w.emit("await using \(op.variableName) = \(input(0));"); + w.emit("await using \(op.variableName) = \(input(0));") w.declare(instr.output, as: op.variableName) case .loadDisposableVariable: - let V = w.declare(instr.output); - w.emit("using \(V) = \(input(0));"); + let V = w.declare(instr.output) + w.emit("using \(V) = \(input(0));") case .loadAsyncDisposableVariable: - let V = w.declare(instr.output); - w.emit("await using \(V) = \(input(0));"); + let V = w.declare(instr.output) + w.emit("await using \(V) = \(input(0));") case .beginObjectLiteral: // We force all expressions to evaluate before the object literal. @@ -452,9 +469,9 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .endObjectLiteralGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralComputedSetter: + .endObjectLiteralSetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralComputedSetter: currentObjectLiteral.endMethod(&w) case .endObjectLiteral: @@ -462,14 +479,16 @@ public class JavaScriptLifter: Lifter { // Everything needs to be written into the object literal writer. let dummy = w.popTemporaryOutputBuffer() // The dummy might still contain the comments. - assert(dummy.isEmpty || dummy.split(separator: "\n").allSatisfy( {$0.hasPrefix("//")})) + assert( + dummy.isEmpty || dummy.split(separator: "\n").allSatisfy({ $0.hasPrefix("//") }) + ) let literal = objectLiteralStack.pop() if literal.isEmpty { w.assign(ObjectLiteral.new("{}"), to: instr.output) } else if literal.canInline { // In this case, we inline the object literal. - let code = "{ \(literal.fields.joined(separator: ", ")) }"; + let code = "{ \(literal.fields.joined(separator: ", ")) }" w.assign(ObjectLiteral.new(code), to: instr.output) } else { let LET = w.declarationKeyword(for: instr.output) @@ -600,11 +619,11 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter: + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter: w.leaveCurrentBlock() w.emit("}") @@ -637,7 +656,8 @@ public class JavaScriptLifter: Lifter { case .createArray: // When creating arrays, treat undefined elements as holes. This also relies on literals always being inlined. - var elems = inputs.map({ $0.text }).map({ $0 == "undefined" ? "" : $0 }).joined(separator: ",") + var elems = inputs.map({ $0.text }).map({ $0 == "undefined" ? "" : $0 }).joined( + separator: ",") if elems.last == "," || (instr.inputs.count == 1 && elems == "") { // If the last element is supposed to be a hole, we need one additional comma elems += "," @@ -663,8 +683,8 @@ public class JavaScriptLifter: Lifter { elems.append(text == "undefined" ? "" : text) } } - var elemString = elems.joined(separator: ","); - if elemString.last == "," || (instr.inputs.count==1 && elemString=="") { + var elemString = elems.joined(separator: ",") + if elemString.last == "," || (instr.inputs.count == 1 && elemString == "") { // If the last element is supposed to be a hole, we need one additional commas elemString += "," } @@ -679,14 +699,17 @@ public class JavaScriptLifter: Lifter { parts.append("${\(VALUE)}\(op.parts[i])") } // See BeginCodeString case. - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let escapeSequence = String(repeating: "\\", count: count) - let expr = TemplateLiteral.new("\(escapeSequence)`" + parts.joined() + "\(escapeSequence)`") + let expr = TemplateLiteral.new( + "\(escapeSequence)`" + parts.joined() + "\(escapeSequence)`") w.assign(expr, to: instr.output) case .getProperty(let op): let obj = input(0) - let expr = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) + let expr = + MemberExpression.new() + obj + + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) w.assign(expr, to: instr.output) case .setProperty(let op): @@ -706,14 +729,17 @@ public class JavaScriptLifter: Lifter { case .deleteProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of a property deletion, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let target = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) + let target = + MemberExpression.new() + obj + + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) let expr = UnaryExpression.new() + "delete " + target w.assign(expr, to: instr.output) case .configureProperty(let op): let OBJ = input(0) let PROPERTY = op.propertyName - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst()) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst()) w.emit("Object.defineProperty(\(OBJ), \"\(PROPERTY)\", \(DESCRIPTOR));") case .getElement(let op): @@ -747,7 +773,8 @@ public class JavaScriptLifter: Lifter { case .configureElement(let op): let OBJ = input(0) let INDEX = op.index - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst()) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst()) w.emit("Object.defineProperty(\(OBJ), \(INDEX), \(DESCRIPTOR));") case .getComputedProperty(let op): @@ -781,7 +808,8 @@ public class JavaScriptLifter: Lifter { case .configureComputedProperty(let op): let OBJ = input(0) let PROPERTY = input(1) - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst(2)) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst(2)) w.emit("Object.defineProperty(\(OBJ), \(PROPERTY), \(DESCRIPTOR));") case .typeOf: @@ -808,8 +836,12 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "function", using: &w) case .beginArrowFunction(let op): - guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } - liftArrowFunctionDefinitionBegin(instr, parameters: op.parameters, isAsync: false, using: &w, functionEndIndex: endIndex, analyzer: analyzer) + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + instr, parameters: op.parameters, isAsync: false, using: &w, + functionEndIndex: endIndex, analyzer: analyzer) case .beginGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "function*", using: &w) @@ -818,14 +850,18 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "async function", using: &w) case .beginAsyncArrowFunction(let op): - guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } - liftArrowFunctionDefinitionBegin(instr, parameters: op.parameters, isAsync: true, using: &w, functionEndIndex: endIndex, analyzer: analyzer) + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + instr, parameters: op.parameters, isAsync: true, using: &w, + functionEndIndex: endIndex, analyzer: analyzer) case .beginAsyncGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "async function*", using: &w) case .endArrowFunction(_), - .endAsyncArrowFunction: + .endAsyncArrowFunction: let state = functionLiftingStack.pop() if state.isSelfReferencing { w.leaveCurrentBlock() @@ -839,12 +875,14 @@ public class JavaScriptLifter: Lifter { let lastInstr = program.code[instr.index - 1] if lastInstr.index > state.startInstructionIndex, - let returnOp = lastInstr.op as? Return, - returnOp.hasReturnValue, - !trimmedBody.contains("\n"), - !trimmedBody.contains("//"), - trimmedBody.hasPrefix("return ") { - let content = trimmedBody.dropFirst("return ".count).trimmingCharacters(in: .whitespaces.union(.init(charactersIn: ";"))) + let returnOp = lastInstr.op as? Return, + returnOp.hasReturnValue, + !trimmedBody.contains("\n"), + !trimmedBody.contains("//"), + trimmedBody.hasPrefix("return ") + { + let content = trimmedBody.dropFirst("return ".count).trimmingCharacters( + in: .whitespaces.union(.init(charactersIn: ";"))) conciseBody = content.hasPrefix("{") ? "(\(content))" : content } @@ -857,9 +895,9 @@ public class JavaScriptLifter: Lifter { } case .endPlainFunction(_), - .endGeneratorFunction(_), - .endAsyncFunction(_), - .endAsyncGeneratorFunction: + .endGeneratorFunction(_), + .endAsyncFunction(_), + .endAsyncGeneratorFunction: w.leaveCurrentBlock() w.emit("}") @@ -919,7 +957,9 @@ public class JavaScriptLifter: Lifter { case .callFunctionWithSpread(let op): let f = inputAsIdentifier(0) let args = inputs.dropFirst() - let expr = CallExpression.new() + f + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + f + "(" + liftCallArguments(args, spreading: op.spreads) + + ")" w.assign(expr, to: instr.output) case .construct: @@ -932,7 +972,9 @@ public class JavaScriptLifter: Lifter { case .constructWithSpread(let op): let f = inputAsIdentifier(0) let args = inputs.dropFirst() - let expr = NewExpression.new() + "new " + f + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + NewExpression.new() + "new " + f + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" // For aesthetic reasons we disallow inlining "new" expressions so that their result is always assigned to a new variable. w.assign(expr, to: instr.output, allowInlining: false) @@ -947,7 +989,9 @@ public class JavaScriptLifter: Lifter { let obj = input(0) let method = MemberExpression.new() + obj + (liftMemberAccess(op.methodName)) let args = inputs.dropFirst() - let expr = CallExpression.new() + method + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + method + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" w.assign(expr, to: instr.output) case .callComputedMethod: @@ -961,7 +1005,9 @@ public class JavaScriptLifter: Lifter { let obj = input(0) let method = MemberExpression.new() + obj + "[" + input(1).text + "]" let args = inputs.dropFirst(2) - let expr = CallExpression.new() + method + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + method + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" w.assign(expr, to: instr.output) case .unaryOperation(let op): @@ -1017,7 +1063,8 @@ public class JavaScriptLifter: Lifter { case .destructArray(let op): let outputs = w.declareAll(instr.outputs) let ARRAY = input(0) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) let LET = w.varKeyword w.emit("\(LET) [\(PATTERN)] = \(ARRAY);") @@ -1025,13 +1072,15 @@ public class JavaScriptLifter: Lifter { assert(inputs.dropFirst().allSatisfy({ $0.type === Identifier })) let ARRAY = input(0) let outputs = inputs.dropFirst().map({ $0.text }) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) w.emit("[\(PATTERN)] = \(ARRAY);") case .destructObject(let op): let outputs = w.declareAll(instr.outputs) let OBJ = input(0) - let PATTERN = liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftObjectDestructPattern( + properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) let LET = w.varKeyword w.emit("\(LET) {\(PATTERN)} = \(OBJ);") @@ -1039,7 +1088,8 @@ public class JavaScriptLifter: Lifter { assert(inputs.dropFirst().allSatisfy({ $0.type === Identifier })) let OBJ = input(0) let outputs = inputs.dropFirst().map({ $0.text }) - let PATTERN = liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftObjectDestructPattern( + properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) w.emit("({\(PATTERN)} = \(OBJ));") case .compare(let op): @@ -1110,7 +1160,7 @@ public class JavaScriptLifter: Lifter { case .callSuperMethod(let op): let method = MemberExpression.new() + "super" + liftMemberAccess(op.methodName) - let expr = CallExpression.new() + method + "(" + liftCallArguments(inputs) + ")" + let expr = CallExpression.new() + method + "(" + liftCallArguments(inputs) + ")" w.assign(expr, to: instr.output) case .getPrivateProperty(let op): @@ -1259,7 +1309,8 @@ public class JavaScriptLifter: Lifter { if w.isCurrentTemporaryBufferEmpty && w.numPendingExpressions == 0 { // The "good" case: we can emit `let i = X, j = Y, ...` assert(loopVars.count == inputs.count) - let declarations = zip(loopVars, inputs).map({ "\($0) = \($1)" }).joined(separator: ", ") + let declarations = zip(loopVars, inputs).map({ "\($0) = \($1)" }).joined( + separator: ", ") initializer = "let \(declarations)" let code = w.popTemporaryOutputBuffer() assert(code.isEmpty) @@ -1274,7 +1325,8 @@ public class JavaScriptLifter: Lifter { initializer = "let \(I) = (() => {\n\(CODE) })()" } else { // Emit a `let [i, j, k] = (() => { ...; return [X, Y, Z]; })()` - let initialLoopVarValues = inputs.map({ $0.text }).joined(separator: ", ") + let initialLoopVarValues = inputs.map({ $0.text }).joined( + separator: ", ") w.emit("return [\(initialLoopVarValues)];") let VARS = loopVars.joined(separator: ", ") let CODE = w.popTemporaryOutputBuffer() @@ -1283,7 +1335,8 @@ public class JavaScriptLifter: Lifter { } } - forLoopHeaderStack.push(ForLoopHeader(initializer: initializer, loopVariables: loopVars)) + forLoopHeaderStack.push( + ForLoopHeader(initializer: initializer, loopVariables: loopVars)) handleBeginSingleExpressionContext(with: &w, initialIndentionLevel: 2) case .beginForLoopAfterthought: @@ -1304,16 +1357,19 @@ public class JavaScriptLifter: Lifter { var CONDITION = header.condition var AFTERTHOUGHT = handleEndSingleExpressionContext(with: &w) - if !INITIALIZER.contains("\n") && !CONDITION.contains("\n") && !AFTERTHOUGHT.contains("\n") { + if !INITIALIZER.contains("\n") && !CONDITION.contains("\n") + && !AFTERTHOUGHT.contains("\n") + { if !CONDITION.isEmpty { CONDITION = " " + CONDITION } if !AFTERTHOUGHT.isEmpty { AFTERTHOUGHT = " " + AFTERTHOUGHT } w.emit("for (\(INITIALIZER);\(CONDITION);\(AFTERTHOUGHT)) {") } else { - w.emitBlock(""" - for (\(INITIALIZER); - \(CONDITION); - \(AFTERTHOUGHT)) { - """) + w.emitBlock( + """ + for (\(INITIALIZER); + \(CONDITION); + \(AFTERTHOUGHT)) { + """) } w.declareAll(instr.innerOutputs, as: header.loopVariables) @@ -1343,7 +1399,8 @@ public class JavaScriptLifter: Lifter { case .beginForOfLoopWithDestruct(let op): let outputs = w.declareAll(instr.innerOutputs) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement) let LET = w.varKeyword let OBJ = input(0) w.emit("for (\(LET) [\(PATTERN)] of \(OBJ)) {") @@ -1370,7 +1427,7 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .loopBreak(_), - .switchBreak: + .switchBreak: w.emit("break;") case .loopContinue: @@ -1402,7 +1459,7 @@ public class JavaScriptLifter: Lifter { case .beginCodeString: // This power series (2**n -1) is used to generate a valid escape sequence for nested template literals. // Here n represents the nesting level. - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let ESCAPE = String(repeating: "\\", count: count) let V = w.declare(instr.output) let LET = w.declarationKeyword(for: instr.output) @@ -1413,7 +1470,7 @@ public class JavaScriptLifter: Lifter { case .endCodeString: codeStringNestingLevel -= 1 w.leaveCurrentBlock() - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let ESCAPE = String(repeating: "\\", count: count) w.emit("\(ESCAPE)`;") @@ -1437,7 +1494,9 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let type = op.value.typeString() let value = op.value.valueToString() - w.emit("\(LET) \(V) = new WebAssembly.Global({ value: \"\(type)\", mutable: \(op.isMutable) }, \(value));") + w.emit( + "\(LET) \(V) = new WebAssembly.Global({ value: \"\(type)\", mutable: \(op.isMutable) }, \(value));" + ) case .createWasmMemory(let op): let V = w.declare(instr.output) @@ -1453,7 +1512,9 @@ public class JavaScriptLifter: Lifter { sharedStr = ", shared: true" } let addressType = isMemory64 ? "'i64'" : "'i32'" - w.emit("\(LET) \(V) = new WebAssembly.Memory({ initial: \(minPageStr)\(maxPagesStr)\(sharedStr), address: \(addressType) });") + w.emit( + "\(LET) \(V) = new WebAssembly.Memory({ initial: \(minPageStr)\(maxPagesStr)\(sharedStr), address: \(addressType) });" + ) case .wrapSuspending(_): let V = w.declare(instr.output) @@ -1494,7 +1555,9 @@ public class JavaScriptLifter: Lifter { let V = w.declare(instr.output, as: "v\(instr.output.number)") // TODO: support a better diagnostics mode which stores the .wasm binary file alongside the samples. do { - let (bytecode, importRefs) = try WasmLifter(withTyper: typer!, withWasmCode: wasmInstructions).lift() + let (bytecode, importRefs) = try WasmLifter( + withTyper: typer!, withWasmCode: wasmInstructions + ).lift() // Get and check that we have the imports here as expressions and fail otherwise. let imports: [(Variable, Expression)] = try importRefs.map { ref in if let expr = w.retrieve(expressionsFor: [ref]) { @@ -1503,11 +1566,17 @@ public class JavaScriptLifter: Lifter { throw WasmLifter.CompileError.failedRetrieval } } - w.emit("\(LET) \(V) = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([") + w.emit( + "\(LET) \(V) = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([" + ) w.enterNewBlock() let blockSize = 10 - for chunk in stride(from: 0, to: bytecode.count, by: blockSize).map({ Array(bytecode[$0 ..< Swift.min($0 + blockSize, bytecode.count)])}) { - let byteString = chunk.map({ String(format: "0x%02X", $0) }).joined(separator: ", ") + "," + for chunk in stride(from: 0, to: bytecode.count, by: blockSize).map({ + Array(bytecode[$0.. String { + private func handleEndSingleExpressionContext( + result maybeResult: Expression? = nil, with w: inout JavaScriptWriter + ) -> String { if w.isCurrentTemporaryBufferEmpty { // This means that the code consists entirely of expressions that can be inlined, and that the result // variable is either not an inlined expression (but instead e.g. the identifier for a local variable), or that @@ -1807,7 +1892,8 @@ public class JavaScriptLifter: Lifter { // // In this case, we can emit a single expression by combining all pending expressions using the comma operator. var COND = CommaExpression.new() - let expressions = w.takePendingExpressions() + (maybeResult != nil ? [maybeResult!] : []) + let expressions = + w.takePendingExpressions() + (maybeResult != nil ? [maybeResult!] : []) for expr in expressions { if COND.text.isEmpty { COND = COND + expr @@ -1841,7 +1927,7 @@ public class JavaScriptLifter: Lifter { } private func liftMemberAccess(_ name: String, isGuarded: Bool = false) -> String { - if environment.isValidDotNotationName(name){ + if environment.isValidDotNotationName(name) { return (isGuarded ? "?." : ".") + name } let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" @@ -1861,7 +1947,9 @@ public class JavaScriptLifter: Lifter { return paramList.joined(separator: ", ") } - private func liftFunctionDefinitionBegin(_ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter) { + private func liftFunctionDefinitionBegin( + _ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter + ) { // Function are lifted as `function f3(a4, a5, a6) { ...`. // This will produce functions with a recognizable .name property, which the JavaScriptExploreLifting code makes use of (see shouldTreatAsConstructor). guard let op = instr.op as? BeginAnyFunction else { @@ -1898,13 +1986,14 @@ public class JavaScriptLifter: Lifter { let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") let params = liftParameters(parameters, as: vars) - functionLiftingStack.push(FunctionLiftingState( - outputVariable: instr.output, - isSelfReferencing: isSelfReferencing, - parameters: params, - isAsync: isAsync, - startInstructionIndex: instr.index - )) + functionLiftingStack.push( + FunctionLiftingState( + outputVariable: instr.output, + isSelfReferencing: isSelfReferencing, + parameters: params, + isAsync: isAsync, + startInstructionIndex: instr.index + )) if isSelfReferencing { let keyword = w.declarationKeyword(for: instr.output) @@ -1918,8 +2007,9 @@ public class JavaScriptLifter: Lifter { } } - - private func liftCallArguments(_ args: Arguments, spreading spreads: [Bool] = []) -> String where Arguments.Element == Expression { + private func liftCallArguments( + _ args: Arguments, spreading spreads: [Bool] = [] + ) -> String where Arguments.Element == Expression { var arguments = [String]() for (i, a) in args.enumerated() { if spreads.count > i && spreads[i] { @@ -1932,7 +2022,9 @@ public class JavaScriptLifter: Lifter { return arguments.joined(separator: ", ") } - private func liftPropertyDescriptor(flags: PropertyFlags, type: PropertyType, values: ArraySlice) -> String { + private func liftPropertyDescriptor( + flags: PropertyFlags, type: PropertyType, values: ArraySlice + ) -> String { assert(values.count <= 2) var parts = [String]() if flags.contains(.writable) { @@ -1960,7 +2052,9 @@ public class JavaScriptLifter: Lifter { return "{ \(parts.joined(separator: ", ")) }" } - private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) -> String { + private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) + -> String + { assert(indices.count == outputs.count) var arrayPattern = "" @@ -1976,7 +2070,9 @@ public class JavaScriptLifter: Lifter { return arrayPattern } - private func liftObjectDestructPattern(properties: [String], outputs: [String], hasRestElement: Bool) -> String { + private func liftObjectDestructPattern( + properties: [String], outputs: [String], hasRestElement: Bool + ) -> String { assert(outputs.count == properties.count + (hasRestElement ? 1 : 0)) var objectPattern = "" @@ -2006,13 +2102,13 @@ public class JavaScriptLifter: Lifter { private func haveSpecialHandlingForGuardedOp(_ op: Operation) -> Bool { switch op.opcode { - // We handle guarded property loads by emitting an optional chain, so no try-catch is necessary. + // We handle guarded property loads by emitting an optional chain, so no try-catch is necessary. case .getProperty, - .getElement, - .getComputedProperty, - .deleteProperty, - .deleteElement, - .deleteComputedProperty: + .getElement, + .getComputedProperty, + .deleteProperty, + .deleteElement, + .deleteComputedProperty: return true default: return false @@ -2066,8 +2162,13 @@ public class JavaScriptLifter: Lifter { // See `reassign()` for more details about reassignment inlining. private var inlinedReassignments = VariableMap() - init(analyzer: DefUseAnalyzer, version: ECMAScriptVersion, stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, alwaysEmitVariables: Bool = false) { - self.writer = ScriptWriter(stripComments: stripComments, includeLineNumbers: includeLineNumbers, indent: indent) + init( + analyzer: DefUseAnalyzer, version: ECMAScriptVersion, stripComments: Bool = false, + includeLineNumbers: Bool = false, indent: Int = 4, alwaysEmitVariables: Bool = false + ) { + self.writer = ScriptWriter( + stripComments: stripComments, includeLineNumbers: includeLineNumbers, indent: indent + ) self.analyzer = analyzer self.varKeyword = version == .es6 ? "let" : "var" self.constKeyword = version == .es6 ? "const" : "var" @@ -2095,7 +2196,9 @@ public class JavaScriptLifter: Lifter { // The expression cannot be inlined. Now decide whether to define the output variable or not. The output variable can be omitted if: // * It is not used by any following instructions, and // * It is not an Object literal, as that would not be valid syntax (it would mistakenly be interpreted as a block statement) - if analyzer.numUses(of: v) == 0 && expr.type !== ObjectLiteral && !alwaysEmitVariables { + if analyzer.numUses(of: v) == 0 && expr.type !== ObjectLiteral + && !alwaysEmitVariables + { emit("\(expr);") } else { let LET = declarationKeyword(for: v) @@ -2146,7 +2249,9 @@ public class JavaScriptLifter: Lifter { /// Otherwise, expression inlining will change the semantics of the program. /// /// This is a mutating operation as it can modify the list of pending expressions or emit pending expression to retain the correct ordering. - mutating func retrieve(expressionsFor queriedVariables: ArraySlice) -> [Expression]? { + mutating func retrieve(expressionsFor queriedVariables: ArraySlice) + -> [Expression]? + { // If any of the expression for the variables is pending, then one of two things will happen: // // 1. Iff the pending expressions that are being retrieved are an exact suffix match of the pending expressions list, then these pending expressions @@ -2182,13 +2287,16 @@ public class JavaScriptLifter: Lifter { // since they can only occur once (otherwise, they wouldn't be inlined), but is important // for inlined reassignments, e.g. to be able to correctly handle `foo(a = 42, a, bar(), a);` var queriedPendingExpressions = [Variable]() - for v in queriedVariables where pendingExpressions.contains(v) && !queriedPendingExpressions.contains(v) { + for v in queriedVariables + where pendingExpressions.contains(v) && !queriedPendingExpressions.contains(v) { queriedPendingExpressions.append(v) } for v in queriedPendingExpressions.reversed() { assert(matchingSuffixLength < pendingExpressions.count) let currentSuffixPosition = pendingExpressions.count - 1 - matchingSuffixLength - if matchingSuffixLength < pendingExpressions.count && v == pendingExpressions[currentSuffixPosition] { + if matchingSuffixLength < pendingExpressions.count + && v == pendingExpressions[currentSuffixPosition] + { matchingSuffixLength += 1 } } @@ -2274,7 +2382,9 @@ public class JavaScriptLifter: Lifter { /// Declare all of the given variables. Equivalent to calling declare() for each of them. /// The variable names will be constructed as prefix + v.number. By default, the prefix "v" is used. @discardableResult - mutating func declareAll(_ vars: Variables, usePrefix prefix: String = "v") -> [String] where Variables.Element == Variable { + mutating func declareAll( + _ vars: Variables, usePrefix prefix: String = "v" + ) -> [String] where Variables.Element == Variable { return vars.map({ declare($0, as: prefix + String($0.number)) }) } @@ -2333,7 +2443,9 @@ public class JavaScriptLifter: Lifter { temporaryOutputBufferStack.push(writer) pendingExpressionsStack.push(pendingExpressions) pendingExpressions = [] - writer = ScriptWriter(stripComments: writer.stripComments, includeLineNumbers: false, indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) + writer = ScriptWriter( + stripComments: writer.stripComments, includeLineNumbers: false, + indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) } mutating func popTemporaryOutputBuffer() -> String { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift index c5347505a..d8f4ed15f 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift @@ -15,137 +15,137 @@ /// This file contains the JavaScript specific implementation of the Probe operation. See ProbingMutator.swift for an overview of this feature. struct JavaScriptProbeLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - - const Probe = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - - // Action constants. - const PROPERTY_LOAD = "loads"; - const PROPERTY_STORE = "stores"; - - // Property access outcomes. - const PROPERTY_NOT_FOUND = 0; - const PROPERTY_FOUND = 1; - - // - // Result recording and reporting. - // - let results = { __proto__: null }; - - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'PROBING_ERROR: ' + msg); - } - - function reportResults() { - fuzzilli('FUZZILLI_PRINT', 'PROBING_RESULTS: ' + stringify(results)); - } - - // Record a property action performed on a probe. - // |target| is expected to be the original prototype of the probe object. It is used to determine whether the accessed property exists anywhere in the prototype chain of the probe. - function recordAction(action, id, target, key) { - let outcome = PROPERTY_NOT_FOUND; - if (ReflectHas(target, key)) { - outcome = PROPERTY_FOUND; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + + const Probe = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + + // Action constants. + const PROPERTY_LOAD = "loads"; + const PROPERTY_STORE = "stores"; + + // Property access outcomes. + const PROPERTY_NOT_FOUND = 0; + const PROPERTY_FOUND = 1; + + // + // Result recording and reporting. + // + let results = { __proto__: null }; + + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'PROBING_ERROR: ' + msg); } - let keyString = key; - if (typeof keyString !== 'string') { - try { - keyString = key.toString(); - if (typeof keyString !== 'string') throw 'not a string'; - } catch(e) { - // Got some "weird" property key. Ignore it. + function reportResults() { + fuzzilli('FUZZILLI_PRINT', 'PROBING_RESULTS: ' + stringify(results)); + } + + // Record a property action performed on a probe. + // |target| is expected to be the original prototype of the probe object. It is used to determine whether the accessed property exists anywhere in the prototype chain of the probe. + function recordAction(action, id, target, key) { + let outcome = PROPERTY_NOT_FOUND; + if (ReflectHas(target, key)) { + outcome = PROPERTY_FOUND; + } + + let keyString = key; + if (typeof keyString !== 'string') { + try { + keyString = key.toString(); + if (typeof keyString !== 'string') throw 'not a string'; + } catch(e) { + // Got some "weird" property key. Ignore it. + return; + } + } + + if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { + // Cannot deal with this property name. Ignore it. return; } - } - if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { - // Cannot deal with this property name. Ignore it. - return; - } + if (isSymbol(key) && !stringStartsWith(keyString, 'Symbol(Symbol.')) { + // We can only deal with well-known symbols (e.g. "Symbol(Symbol.toPrimitive)"), and this isn't one. Ignore it. + return; + } - if (isSymbol(key) && !stringStartsWith(keyString, 'Symbol(Symbol.')) { - // We can only deal with well-known symbols (e.g. "Symbol(Symbol.toPrimitive)"), and this isn't one. Ignore it. - return; + if (!hasOwnProperty(results, id)) { + results[id] = { [PROPERTY_LOAD]: { __proto__: null }, [PROPERTY_STORE]: { __proto__: null } }; + } + + // If the same action is performed on the same probe multiple times, we keep the last result. + results[id][action][keyString] = outcome; } - if (!hasOwnProperty(results, id)) { - results[id] = { [PROPERTY_LOAD]: { __proto__: null }, [PROPERTY_STORE]: { __proto__: null } }; + function recordActionWithErrorHandling(action, id, target, key) { + try { + recordAction(action, id, target, key); + } catch(e) { + reportError(e); + } } - // If the same action is performed on the same probe multiple times, we keep the last result. - results[id][action][keyString] = outcome; - } + // + // Probe implementation. + // + function probe(id, value) { + let originalPrototype, newPrototype; + let handler = { + get(target, key, receiver) { + // Special logic to deal with programs that fetch the prototype of an object after it was turned into a probe. + // In that case, the probe Proxy would leak to the script, potentially causing incorrect behaviour. To deal with that, + // we (1) return the original prototype when __proto__ is loaded (but this can be "bypassed" through Object.getPrototypeOf) + // and (2) attempt to detect property accesses on the prototype itself (instead of on the probe) and handle those separately. + if (key === '__proto__' && receiver === value) return originalPrototype; + if (receiver === newPrototype) return ReflectGet(target, key); + recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); + return ReflectGet(target, key, receiver); + }, + set(target, key, value, receiver) { + if (receiver === newPrototype) return ReflectSet(target, key, value); + recordActionWithErrorHandling(PROPERTY_STORE, id, target, key); + return ReflectSet(target, key, value, receiver); + }, + has(target, key) { + // Treat this as a load. + recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); + return ReflectHas(target, key); + }, + }; - function recordActionWithErrorHandling(action, id, target, key) { - try { - recordAction(action, id, target, key); - } catch(e) { - reportError(e); + try { + // This can fail, e.g. due to "Cannot convert undefined or null to object" or if the object is non-extensible. In that case, do nothing. + originalPrototype = getPrototypeOf(value); + newPrototype = new ProxyConstructor(originalPrototype, handler); + setPrototypeOf(value, newPrototype); + } catch (e) {} } - } - - // - // Probe implementation. - // - function probe(id, value) { - let originalPrototype, newPrototype; - let handler = { - get(target, key, receiver) { - // Special logic to deal with programs that fetch the prototype of an object after it was turned into a probe. - // In that case, the probe Proxy would leak to the script, potentially causing incorrect behaviour. To deal with that, - // we (1) return the original prototype when __proto__ is loaded (but this can be "bypassed" through Object.getPrototypeOf) - // and (2) attempt to detect property accesses on the prototype itself (instead of on the probe) and handle those separately. - if (key === '__proto__' && receiver === value) return originalPrototype; - if (receiver === newPrototype) return ReflectGet(target, key); - recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); - return ReflectGet(target, key, receiver); - }, - set(target, key, value, receiver) { - if (receiver === newPrototype) return ReflectSet(target, key, value); - recordActionWithErrorHandling(PROPERTY_STORE, id, target, key); - return ReflectSet(target, key, value, receiver); - }, - has(target, key) { - // Treat this as a load. - recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); - return ReflectHas(target, key); - }, - }; - try { - // This can fail, e.g. due to "Cannot convert undefined or null to object" or if the object is non-extensible. In that case, do nothing. - originalPrototype = getPrototypeOf(value); - newPrototype = new ProxyConstructor(originalPrototype, handler); - setPrototypeOf(value, newPrototype); - } catch (e) {} - } - - function probeWithErrorHandling(id, value) { - try { - probe(id, value); - } catch(e) { - reportError(e); + function probeWithErrorHandling(id, value) { + try { + probe(id, value); + } catch(e) { + reportError(e); + } } - } - return { - probe: probeWithErrorHandling, - reportResults: reportResults - }; - })(); + return { + probe: probeWithErrorHandling, + reportResults: reportResults + }; + })(); - """ + """ static let probeFunc = "Probe.probe" static let suffixCode = """ - Probe.reportResults(); + Probe.reportResults(); - """ + """ } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index 17fba9d87..9b2448dbb 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -15,577 +15,577 @@ /// This file contains the JavaScript specific implementation of common runtime-assisted logic, such as the JS struct JavaScriptRuntimeAssistedMutatorLifting { static let commonCode = """ - // Note: runtime instrumentation code must generally assume that any operation performed on any object coming from the "outside", may raise an exception, for example due to triggering a Proxy trap. - // Further, it must also assume that the environment has been modified arbitrarily. For example, the Array.prototype[@@iterator] may have been set to an invalid value, so using `for...of` syntax could trigger an exception. - - // Load all necessary routines and objects into local variables as they may be overwritten by the program. - // We generally want to avoid triggerring observable side-effects, such as storing or loading - // properties. For that reason, we prefer to use builtins like Object.defineProperty. - - const ProxyConstructor = Proxy; - const BigIntConstructor = BigInt; - const SetConstructor = Set; - - const ObjectPrototype = Object.prototype; - - const getOwnPropertyNames = Object.getOwnPropertyNames; - const getPrototypeOf = Object.getPrototypeOf; - const setPrototypeOf = Object.setPrototypeOf; - const stringify = JSON.stringify; - const hasOwnProperty = Object.hasOwn; - const defineProperty = Object.defineProperty; - const propertyValues = Object.values; - const parseInteger = parseInt; - const NumberIsInteger = Number.isInteger; - const isNaN = Number.isNaN; - const isFinite = Number.isFinite; - const truncate = Math.trunc; - const apply = Reflect.apply; - const construct = Reflect.construct; - const ReflectGet = Reflect.get; - const ReflectSet = Reflect.set; - const ReflectHas = Reflect.has; - - // Bind methods to local variables. These all expect the 'this' object as first parameter. - const concat = Function.prototype.call.bind(Array.prototype.concat); - const findIndex = Function.prototype.call.bind(Array.prototype.findIndex); - const includes = Function.prototype.call.bind(Array.prototype.includes); - const shift = Function.prototype.call.bind(Array.prototype.shift); - const pop = Function.prototype.call.bind(Array.prototype.pop); - const push = Function.prototype.call.bind(Array.prototype.push); - const filter = Function.prototype.call.bind(Array.prototype.filter); - const execRegExp = Function.prototype.call.bind(RegExp.prototype.exec); - const stringSlice = Function.prototype.call.bind(String.prototype.slice); - const toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase); - const numberToString = Function.prototype.call.bind(Number.prototype.toString); - const bigintToString = Function.prototype.call.bind(BigInt.prototype.toString); - const stringStartsWith = Function.prototype.call.bind(String.prototype.startsWith); - const setAdd = Function.prototype.call.bind(Set.prototype.add); - const setHas = Function.prototype.call.bind(Set.prototype.has); - - const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER; - const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; - - // Simple, seedable PRNG based on a LCG. - class RNG { - m = 2 ** 32; - a = 1664525; - c = 1013904223; - x; - - constructor(seed) { - this.x = seed; - } - randomInt() { - this.x = (this.x * this.a + this.c) % this.m; - if (!isInteger(this.x)) throw "RNG state is not an Integer!" - return this.x; - } - randomFloat() { - return this.randomInt() / this.m; - } - probability(p) { - return this.randomFloat() < p; - } - reseed(seed) { - this.x = seed; - } - } - - // When creating empty arrays to which elements are later added, use a custom array type that has a null prototype. This way, the arrays are not - // affected by changes to the Array.prototype that could interfere with array builtins (e.g. indexed setters or a modified .constructor property). - function EmptyArray() { - let array = []; - setPrototypeOf(array, null); - return array; - } - - // - // Misc. helper functions. - // - // Type check helpers. These are less error-prone than manually using typeof and comparing against a string. - function isObject(v) { - return typeof v === 'object'; - } - function isFunction(v) { - return typeof v === 'function'; - } - function isString(v) { - return typeof v === 'string'; - } - function isNumber(v) { - return typeof v === 'number'; - } - function isBigint(v) { - return typeof v === 'bigint'; - } - function isSymbol(v) { - return typeof v === 'symbol'; - } - function isBoolean(v) { - return typeof v === 'boolean'; - } - function isUndefined(v) { - return typeof v === 'undefined'; - } - - // Helper function to determine if a value is an integer, and within [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER]. - function isInteger(n) { - return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; - } - - // Helper function to determine if a string is short. - function isShortString(s) { - if (!isString(s)) throw "Non-string argument to isShortString: " + s; - return s.length < 50; - } - - // Helper function to determine if a string is numeric and its numeric value representable as an integer. - function isNumericString(s) { - if (!isString(s)) return false; - let number = parseInteger(s); - return number >= MIN_SAFE_INTEGER && number <= MAX_SAFE_INTEGER && numberToString(number) === s; - } - - // Helper function to determine whether a property can be accessed without raising an exception. - function tryAccessProperty(prop, obj) { - try { - obj[prop]; - return true; - } catch (e) { - return false; - } - } - - // Helper function to determine if a property exists on an object or one of its prototypes. If an exception is raised, false is returned. - function tryHasProperty(prop, obj) { - try { - return prop in obj; - } catch (e) { - return false; - } - } - - // Helper function to load a property from an object. If an exception is raised, undefined is returned. - function tryGetProperty(prop, obj) { - try { - return obj[prop]; - } catch (e) { - return undefined; - } - } - - // Helper function to obtain the own properties of an object. If that raises an exception (e.g. on a Proxy object), an empty array is returned. - function tryGetOwnPropertyNames(obj) { - try { - return getOwnPropertyNames(obj); - } catch (e) { - return new Array(); - } - } - - // Helper function to fetch the prototype of an object. If that raises an exception (e.g. on a Proxy object), null is returned. - function tryGetPrototypeOf(obj) { - try { - return getPrototypeOf(obj); - } catch (e) { - return null; - } - } - - // Helper function to that creates a wrapper function for the given function which will call it in a try-catch and return false on exception. - function wrapInTryCatch(f) { - return function() { + // Note: runtime instrumentation code must generally assume that any operation performed on any object coming from the "outside", may raise an exception, for example due to triggering a Proxy trap. + // Further, it must also assume that the environment has been modified arbitrarily. For example, the Array.prototype[@@iterator] may have been set to an invalid value, so using `for...of` syntax could trigger an exception. + + // Load all necessary routines and objects into local variables as they may be overwritten by the program. + // We generally want to avoid triggerring observable side-effects, such as storing or loading + // properties. For that reason, we prefer to use builtins like Object.defineProperty. + + const ProxyConstructor = Proxy; + const BigIntConstructor = BigInt; + const SetConstructor = Set; + + const ObjectPrototype = Object.prototype; + + const getOwnPropertyNames = Object.getOwnPropertyNames; + const getPrototypeOf = Object.getPrototypeOf; + const setPrototypeOf = Object.setPrototypeOf; + const stringify = JSON.stringify; + const hasOwnProperty = Object.hasOwn; + const defineProperty = Object.defineProperty; + const propertyValues = Object.values; + const parseInteger = parseInt; + const NumberIsInteger = Number.isInteger; + const isNaN = Number.isNaN; + const isFinite = Number.isFinite; + const truncate = Math.trunc; + const apply = Reflect.apply; + const construct = Reflect.construct; + const ReflectGet = Reflect.get; + const ReflectSet = Reflect.set; + const ReflectHas = Reflect.has; + + // Bind methods to local variables. These all expect the 'this' object as first parameter. + const concat = Function.prototype.call.bind(Array.prototype.concat); + const findIndex = Function.prototype.call.bind(Array.prototype.findIndex); + const includes = Function.prototype.call.bind(Array.prototype.includes); + const shift = Function.prototype.call.bind(Array.prototype.shift); + const pop = Function.prototype.call.bind(Array.prototype.pop); + const push = Function.prototype.call.bind(Array.prototype.push); + const filter = Function.prototype.call.bind(Array.prototype.filter); + const execRegExp = Function.prototype.call.bind(RegExp.prototype.exec); + const stringSlice = Function.prototype.call.bind(String.prototype.slice); + const toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase); + const numberToString = Function.prototype.call.bind(Number.prototype.toString); + const bigintToString = Function.prototype.call.bind(BigInt.prototype.toString); + const stringStartsWith = Function.prototype.call.bind(String.prototype.startsWith); + const setAdd = Function.prototype.call.bind(Set.prototype.add); + const setHas = Function.prototype.call.bind(Set.prototype.has); + + const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER; + const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; + + // Simple, seedable PRNG based on a LCG. + class RNG { + m = 2 ** 32; + a = 1664525; + c = 1013904223; + x; + + constructor(seed) { + this.x = seed; + } + randomInt() { + this.x = (this.x * this.a + this.c) % this.m; + if (!isInteger(this.x)) throw "RNG state is not an Integer!" + return this.x; + } + randomFloat() { + return this.randomInt() / this.m; + } + probability(p) { + return this.randomFloat() < p; + } + reseed(seed) { + this.x = seed; + } + } + + // When creating empty arrays to which elements are later added, use a custom array type that has a null prototype. This way, the arrays are not + // affected by changes to the Array.prototype that could interfere with array builtins (e.g. indexed setters or a modified .constructor property). + function EmptyArray() { + let array = []; + setPrototypeOf(array, null); + return array; + } + + // + // Misc. helper functions. + // + // Type check helpers. These are less error-prone than manually using typeof and comparing against a string. + function isObject(v) { + return typeof v === 'object'; + } + function isFunction(v) { + return typeof v === 'function'; + } + function isString(v) { + return typeof v === 'string'; + } + function isNumber(v) { + return typeof v === 'number'; + } + function isBigint(v) { + return typeof v === 'bigint'; + } + function isSymbol(v) { + return typeof v === 'symbol'; + } + function isBoolean(v) { + return typeof v === 'boolean'; + } + function isUndefined(v) { + return typeof v === 'undefined'; + } + + // Helper function to determine if a value is an integer, and within [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER]. + function isInteger(n) { + return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; + } + + // Helper function to determine if a string is short. + function isShortString(s) { + if (!isString(s)) throw "Non-string argument to isShortString: " + s; + return s.length < 50; + } + + // Helper function to determine if a string is numeric and its numeric value representable as an integer. + function isNumericString(s) { + if (!isString(s)) return false; + let number = parseInteger(s); + return number >= MIN_SAFE_INTEGER && number <= MAX_SAFE_INTEGER && numberToString(number) === s; + } + + // Helper function to determine whether a property can be accessed without raising an exception. + function tryAccessProperty(prop, obj) { try { - return apply(f, this, arguments); + obj[prop]; + return true; } catch (e) { return false; } - }; - } - - // - // Basic random number generation utility functions. - // - - // Initially the rng is seeded randomly, specific mutators can reseed() the rng if they need deterministic behavior. - // See the explore operation in JsOperations.swift for an example. - let rng = new RNG(truncate(Math.random() * 2**32)); - - function probability(p) { - if (p < 0 || p > 1) throw "Argument to probability must be a number between zero and one"; - return rng.probability(p); - } - - function randomIntBetween(start, end) { - if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; - return (rng.randomInt() % (end - start)) + start; - } - - function randomFloat() { - return rng.randomFloat(); - } - - function randomBigintBetween(start, end) { - if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; - if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular intergers"; - return BigIntConstructor(randomIntBetween(Number(start), Number(end))); - } - - function randomIntBelow(n) { - if (!isInteger(n)) throw "Argument to randomIntBelow must be an integer"; - return rng.randomInt() % n; - } - - function randomElement(array) { - return array[randomIntBelow(array.length)]; - } - """ + } - static let introspectionCode = """ - // Note: this code assumes that the common code from above has been included before. - - // - // Object introspection. - // - - // - // Enumerate all properties on the given object and its prototypes. - // - // These include elements and methods (callable properties). Each property is assigned a "weight" which expresses roughly how "important"/"interesting" a property is: - // a property that exists on a prototype is considered less interesting as it can probably be reached through other objects as well, so we prefer properties closer to the start object. - // - // The result is returned in an array like the following: - // [ - // length: - // totalWeight: - // 0, 1, ..., length - 1: { name: , weight: } - // ] - function enumeratePropertiesOf(o) { - // Collect all properties, including those from prototypes, in this array. - let properties = EmptyArray(); - - // Give properties from prototypes a lower weight. Currently, the weight is halved for every new level of the prototype chain. - let currentWeight = 1.0; - properties.totalWeight = 0.0; - function recordProperty(p) { - push(properties, {name: p, weight: currentWeight}); - properties.totalWeight += currentWeight; - } - - // Iterate over the prototype chain and record all properties. - let obj = o; - while (obj !== null) { - // Special handling for array-like things: if the array is too large, skip this level and just include a couple random indices. - // We need to be careful when accessing the length though: for TypedArrays, the length property is defined on the prototype but - // must be accessed with the TypedArray as |this| value (not the prototype). - let maybeLength = tryGetProperty('length', obj); - if (isInteger(maybeLength) && maybeLength > 100) { - for (let i = 0; i < 10; i++) { - let randomElement = randomIntBelow(maybeLength); - recordProperty(randomElement); + // Helper function to determine if a property exists on an object or one of its prototypes. If an exception is raised, false is returned. + function tryHasProperty(prop, obj) { + try { + return prop in obj; + } catch (e) { + return false; + } + } + + // Helper function to load a property from an object. If an exception is raised, undefined is returned. + function tryGetProperty(prop, obj) { + try { + return obj[prop]; + } catch (e) { + return undefined; + } + } + + // Helper function to obtain the own properties of an object. If that raises an exception (e.g. on a Proxy object), an empty array is returned. + function tryGetOwnPropertyNames(obj) { + try { + return getOwnPropertyNames(obj); + } catch (e) { + return new Array(); + } + } + + // Helper function to fetch the prototype of an object. If that raises an exception (e.g. on a Proxy object), null is returned. + function tryGetPrototypeOf(obj) { + try { + return getPrototypeOf(obj); + } catch (e) { + return null; + } + } + + // Helper function to that creates a wrapper function for the given function which will call it in a try-catch and return false on exception. + function wrapInTryCatch(f) { + return function() { + try { + return apply(f, this, arguments); + } catch (e) { + return false; } - } else { - // TODO do we want to also enumerate symbol properties here (using Object.getOwnPropertySymbols)? If we do, we should probable also add IL-level support for Symbols (i.e. a `LoadSymbol` instruction that ensures the symbol is in the global Symbol registry). - let allOwnPropertyNames = tryGetOwnPropertyNames(obj); - let allOwnElements = EmptyArray(); - for (let i = 0; i < allOwnPropertyNames.length; i++) { - let p = allOwnPropertyNames[i]; - let index = parseInteger(p); - // TODO should we allow negative indices here as well? - if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { - push(allOwnElements, index); - } else if (isShortString(p) && tryAccessProperty(p, o)) { - // Only include properties with short names and only if they can be accessed on the original object without raising an exception. - recordProperty(p); + }; + } + + // + // Basic random number generation utility functions. + // + + // Initially the rng is seeded randomly, specific mutators can reseed() the rng if they need deterministic behavior. + // See the explore operation in JsOperations.swift for an example. + let rng = new RNG(truncate(Math.random() * 2**32)); + + function probability(p) { + if (p < 0 || p > 1) throw "Argument to probability must be a number between zero and one"; + return rng.probability(p); + } + + function randomIntBetween(start, end) { + if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; + return (rng.randomInt() % (end - start)) + start; + } + + function randomFloat() { + return rng.randomFloat(); + } + + function randomBigintBetween(start, end) { + if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; + if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular intergers"; + return BigIntConstructor(randomIntBetween(Number(start), Number(end))); + } + + function randomIntBelow(n) { + if (!isInteger(n)) throw "Argument to randomIntBelow must be an integer"; + return rng.randomInt() % n; + } + + function randomElement(array) { + return array[randomIntBelow(array.length)]; + } + """ + + static let introspectionCode = """ + // Note: this code assumes that the common code from above has been included before. + + // + // Object introspection. + // + + // + // Enumerate all properties on the given object and its prototypes. + // + // These include elements and methods (callable properties). Each property is assigned a "weight" which expresses roughly how "important"/"interesting" a property is: + // a property that exists on a prototype is considered less interesting as it can probably be reached through other objects as well, so we prefer properties closer to the start object. + // + // The result is returned in an array like the following: + // [ + // length: + // totalWeight: + // 0, 1, ..., length - 1: { name: , weight: } + // ] + function enumeratePropertiesOf(o) { + // Collect all properties, including those from prototypes, in this array. + let properties = EmptyArray(); + + // Give properties from prototypes a lower weight. Currently, the weight is halved for every new level of the prototype chain. + let currentWeight = 1.0; + properties.totalWeight = 0.0; + function recordProperty(p) { + push(properties, {name: p, weight: currentWeight}); + properties.totalWeight += currentWeight; + } + + // Iterate over the prototype chain and record all properties. + let obj = o; + while (obj !== null) { + // Special handling for array-like things: if the array is too large, skip this level and just include a couple random indices. + // We need to be careful when accessing the length though: for TypedArrays, the length property is defined on the prototype but + // must be accessed with the TypedArray as |this| value (not the prototype). + let maybeLength = tryGetProperty('length', obj); + if (isInteger(maybeLength) && maybeLength > 100) { + for (let i = 0; i < 10; i++) { + let randomElement = randomIntBelow(maybeLength); + recordProperty(randomElement); + } + } else { + // TODO do we want to also enumerate symbol properties here (using Object.getOwnPropertySymbols)? If we do, we should probable also add IL-level support for Symbols (i.e. a `LoadSymbol` instruction that ensures the symbol is in the global Symbol registry). + let allOwnPropertyNames = tryGetOwnPropertyNames(obj); + let allOwnElements = EmptyArray(); + for (let i = 0; i < allOwnPropertyNames.length; i++) { + let p = allOwnPropertyNames[i]; + let index = parseInteger(p); + // TODO should we allow negative indices here as well? + if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { + push(allOwnElements, index); + } else if (isShortString(p) && tryAccessProperty(p, o)) { + // Only include properties with short names and only if they can be accessed on the original object without raising an exception. + recordProperty(p); + } } - } - // Limit array-like objects to at most 10 random elements. - for (let i = 0; i < 10 && allOwnElements.length > 0; i++) { - let index = randomIntBelow(allOwnElements.length); - recordProperty(allOwnElements[index]); - allOwnElements[index] = pop(allOwnElements); + // Limit array-like objects to at most 10 random elements. + for (let i = 0; i < 10 && allOwnElements.length > 0; i++) { + let index = randomIntBelow(allOwnElements.length); + recordProperty(allOwnElements[index]); + allOwnElements[index] = pop(allOwnElements); + } } - } - obj = tryGetPrototypeOf(obj); - currentWeight /= 2.0; + obj = tryGetPrototypeOf(obj); + currentWeight /= 2.0; - // Greatly reduce the property weights for the Object.prototype. These methods are always available and we can use more targeted mechanisms like CodeGenerators to call them if we want to. - if (obj === ObjectPrototype) { - // Somewhat arbitrarily reduce the weight as if there were another 3 levels. - currentWeight /= 8.0; + // Greatly reduce the property weights for the Object.prototype. These methods are always available and we can use more targeted mechanisms like CodeGenerators to call them if we want to. + if (obj === ObjectPrototype) { + // Somewhat arbitrarily reduce the weight as if there were another 3 levels. + currentWeight /= 8.0; - // However, if we've reached the Object prototype without any other properties (i.e. are inspecting an empty, plain object), then always return an empty list since these properties are not very intersting. - if (properties.length == 0) { - return properties; + // However, if we've reached the Object prototype without any other properties (i.e. are inspecting an empty, plain object), then always return an empty list since these properties are not very intersting. + if (properties.length == 0) { + return properties; + } } } + + return properties; } - return properties; - } - - // - // Returns a random property available on the given object or one of its prototypes. - // - // This will return more "interesting" properties with a higher probability. In general, properties closer to the start object - // are preferred over properties on prototypes (as these are likely shared with other objects). - // - // If no (interesting) property exists, null is returned. Otherwise, the key of the property is returned. - function randomPropertyOf(o) { - let properties = enumeratePropertiesOf(o); - - // We need at least one property to chose from. - if (properties.length === 0) { - return null; - } - - // Now choose a random property. If a property has weight 2W, it will be selected with twice the probability of a property with weight W. - let selectedProperty; - let remainingWeight = randomFloat() * properties.totalWeight; - for (let i = 0; i < properties.length; i++) { - let candidate = properties[i]; - remainingWeight -= candidate.weight; - if (remainingWeight < 0) { - selectedProperty = candidate.name; - break; + // + // Returns a random property available on the given object or one of its prototypes. + // + // This will return more "interesting" properties with a higher probability. In general, properties closer to the start object + // are preferred over properties on prototypes (as these are likely shared with other objects). + // + // If no (interesting) property exists, null is returned. Otherwise, the key of the property is returned. + function randomPropertyOf(o) { + let properties = enumeratePropertiesOf(o); + + // We need at least one property to chose from. + if (properties.length === 0) { + return null; + } + + // Now choose a random property. If a property has weight 2W, it will be selected with twice the probability of a property with weight W. + let selectedProperty; + let remainingWeight = randomFloat() * properties.totalWeight; + for (let i = 0; i < properties.length; i++) { + let candidate = properties[i]; + remainingWeight -= candidate.weight; + if (remainingWeight < 0) { + selectedProperty = candidate.name; + break; + } } - } - // Sanity checking. This may fail for example if Proxies are involved. In that case, just fail here. - if (!tryHasProperty(selectedProperty, o)) return null; + // Sanity checking. This may fail for example if Proxies are involved. In that case, just fail here. + if (!tryHasProperty(selectedProperty, o)) return null; - return selectedProperty; - } - """ + return selectedProperty; + } + """ static let actionCode = """ - // Note: this code assumes that the common code from above has been included before. - - // - // List of all supported operations. Must be kept in sync with the ActionOperation enum. - // - const OP_CALL_FUNCTION = 'CALL_FUNCTION'; - const OP_CONSTRUCT = 'CONSTRUCT'; - const OP_CALL_METHOD = 'CALL_METHOD'; - const OP_CONSTRUCT_METHOD = 'CONSTRUCT_METHOD'; - const OP_GET_PROPERTY = 'GET_PROPERTY'; - const OP_SET_PROPERTY = 'SET_PROPERTY'; - const OP_DELETE_PROPERTY = 'DELETE_PROPERTY'; - - const OP_ADD = 'ADD'; - const OP_SUB = 'SUB'; - const OP_MUL = 'MUL'; - const OP_DIV = 'DIV'; - const OP_MOD = 'MOD'; - const OP_INC = 'INC'; - const OP_DEC = 'DEC'; - const OP_NEG = 'NEG'; - - const OP_LOGICAL_AND = 'LOGICAL_AND'; - const OP_LOGICAL_OR = 'LOGICAL_OR'; - const OP_LOGICAL_NOT = 'LOGICAL_NOT'; - const OP_NULL_COALESCE = 'NULL_COALESCE'; - - const OP_BITWISE_AND = 'BITWISE_AND'; - const OP_BITWISE_OR = 'BITWISE_OR'; - const OP_BITWISE_XOR = 'BITWISE_XOR'; - const OP_LEFT_SHIFT = 'LEFT_SHIFT'; - const OP_SIGNED_RIGHT_SHIFT = 'SIGNED_RIGHT_SHIFT'; - const OP_UNSIGNED_RIGHT_SHIFT = 'UNSIGNED_RIGHT_SHIFT'; - const OP_BITWISE_NOT = 'BITWISE_NOT'; - - const OP_COMPARE_EQUAL = 'COMPARE_EQUAL'; - const OP_COMPARE_STRICT_EQUAL = 'COMPARE_STRICT_EQUAL'; - const OP_COMPARE_NOT_EQUAL = 'COMPARE_NOT_EQUAL'; - const OP_COMPARE_STRICT_NOT_EQUAL = 'COMPARE_STRICT_NOT_EQUAL'; - const OP_COMPARE_GREATER_THAN = 'COMPARE_GREATER_THAN'; - const OP_COMPARE_LESS_THAN = 'COMPARE_LESS_THAN'; - const OP_COMPARE_GREATER_THAN_OR_EQUAL = 'COMPARE_GREATER_THAN_OR_EQUAL'; - const OP_COMPARE_LESS_THAN_OR_EQUAL = 'COMPARE_LESS_THAN_OR_EQUAL'; - const OP_TEST_IS_NAN = 'TEST_IS_NAN'; - const OP_TEST_IS_FINITE = 'TEST_IS_FINITE'; - - const OP_SYMBOL_REGISTRATION = 'SYMBOL_REGISTRATION'; - - // - // Action constructors. - // - function Action(operation, inputs) { - this.operation = operation; - this.inputs = inputs; - this.isGuarded = false; - } - - // A guarded action is an action that is allowed to raise an exception. - // - // These are for example used for by the ExplorationMutator for function/method call - // which may throw an exception if they aren't given the right arguments. In that case, - // we may still want to keep the function call so that it can be mutated further to - // hopefully eventually find the correct arguments. This is especially true if finding - // the right arguments reqires the ProbingMutator to install the right properties on an - // argument object, in which case the ExplorationMutator on its own would (likely) never - // be able to generate a valid call, and so the function/method may be missed entirely. - // - // If a guarded action succeeds (doesn't raise an exception), it will be converted to - // a regular action to limit the number of generated try-catch blocks. - function GuardedAction(operation, inputs) { - this.operation = operation; - this.inputs = inputs; - this.isGuarded = true; - } - - // Special value to indicate that no action should be performed. - const NO_ACTION = null; - - // - // Action Input constructors. - // - // The inputs for actions are encoded as objects that specify both the type and the value of the input. They are basically enum values with associated values. - // These must be kept compatible with the Action.Input enum in RuntimeAssistedMutator.swift as they have to be encodable to/decodable from that enum. - // - function ArgumentInput(index) { - if (!isInteger(index)) throw "ArgumentInput index is not an integer: " + index; - return { argument: { index } }; - } - function SpecialInput(name) { - if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; - return { special: { name } }; - } - function IntInput(value) { - if (!isInteger(value)) throw "IntInput value is not an integer: " + value; - return { int: { value } }; - } - function FloatInput(value) { - if (!isNumber(value) || !isFinite(value)) throw "FloatInput value is not a (finite) number: " + value; - return { float: { value } }; - } - function BigintInput(value) { - if (!isBigint(value)) throw "BigintInput value is not a bigint: " + value; - // Bigints can't be serialized by JSON.stringify, so store them as strings instead. - return { bigint: { value: bigintToString(value) } }; - } - function StringInput(value) { - if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; - return { string: { value } }; - } - - // Type checkers for Input objects. We use these instead of for example 'instanceof' since we allow Input - // objects to be decoded from JSON, in which case they will not have the right .constructor property. - function isArgumentInput(input) { return hasOwnProperty(input, 'argument'); } - function isSpecialInput(input) { return hasOwnProperty(input, 'special'); } - function isIntInput(input) { return hasOwnProperty(input, 'int'); } - function isFloatInput(input) { return hasOwnProperty(input, 'float'); } - function isBigintInput(input) { return hasOwnProperty(input, 'bigint'); } - function isStringInput(input) { return hasOwnProperty(input, 'string'); } - - // Helper routines to extract the associated values from Input objects. - function getArgumentInputIndex(input) { return input.argument.index; } - function getSpecialInputName(input) { return input.special.name; } - function getIntInputValue(input) { return input.int.value; } - function getFloatInputValue(input) { return input.float.value; } - function getBigintInputValue(input) { return BigIntConstructor(input.bigint.value); } - function getStringInputValue(input) { return input.string.value; } - - // Handlers for executing actions. - // These will receive the array of concrete inputs (i.e. JavaScript values) as first parameter and the current value of |this| as second parameter (which can be ignored if not needed). - const ACTION_HANDLERS = { - [OP_CALL_FUNCTION]: (inputs, currentThis) => { let f = shift(inputs); return apply(f, currentThis, inputs); }, - [OP_CONSTRUCT]: (inputs) => { let c = shift(inputs); return construct(c, inputs); }, - [OP_CALL_METHOD]: (inputs) => { let o = shift(inputs); let m = shift(inputs); return apply(o[m], o, inputs); }, - [OP_CONSTRUCT_METHOD]: (v, inputs) => { let o = shift(inputs); let m = shift(inputs); return construct(o[m], inputs); }, - [OP_GET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return o[p]; }, - [OP_SET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; let v = inputs[2]; o[p] = v; }, - [OP_DELETE_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return delete o[p]; }, - [OP_ADD]: (inputs) => inputs[0] + inputs[1], - [OP_SUB]: (inputs) => inputs[0] - inputs[1], - [OP_MUL]: (inputs) => inputs[0] * inputs[1], - [OP_DIV]: (inputs) => inputs[0] / inputs[1], - [OP_MOD]: (inputs) => inputs[0] % inputs[1], - [OP_INC]: (inputs) => inputs[0]++, - [OP_DEC]: (inputs) => inputs[0]--, - [OP_NEG]: (inputs) => -inputs[0], - [OP_LOGICAL_AND]: (inputs) => inputs[0] && inputs[1], - [OP_LOGICAL_OR]: (inputs) => inputs[0] || inputs[1], - [OP_LOGICAL_NOT]: (inputs) => !inputs[0], - [OP_NULL_COALESCE]: (inputs) => inputs[0] ?? inputs[1], - [OP_BITWISE_AND]: (inputs) => inputs[0] & inputs[1], - [OP_BITWISE_OR]: (inputs) => inputs[0] | inputs[1], - [OP_BITWISE_XOR]: (inputs) => inputs[0] ^ inputs[1], - [OP_LEFT_SHIFT]: (inputs) => inputs[0] << inputs[1], - [OP_SIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >> inputs[1], - [OP_UNSIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >>> inputs[1], - [OP_BITWISE_NOT]: (inputs) => ~inputs[0], - [OP_COMPARE_EQUAL]: (inputs) => inputs[0] == inputs[1], - [OP_COMPARE_STRICT_EQUAL]: (inputs) => inputs[0] === inputs[1], - [OP_COMPARE_NOT_EQUAL]: (inputs) => inputs[0] != inputs[1], - [OP_COMPARE_STRICT_NOT_EQUAL]: (inputs) => inputs[0] !== inputs[1], - [OP_COMPARE_GREATER_THAN]: (inputs) => inputs[0] > inputs[1], - [OP_COMPARE_LESS_THAN]: (inputs) => inputs[0] < inputs[1], - [OP_COMPARE_GREATER_THAN_OR_EQUAL]: (inputs) => inputs[0] >= inputs[1], - [OP_COMPARE_LESS_THAN_OR_EQUAL]: (inputs) => inputs[0] <= inputs[1], - [OP_TEST_IS_NAN]: (inputs) => Number.isNaN(inputs[0]), - [OP_TEST_IS_FINITE]: (inputs) => Number.isFinite(inputs[0]), - [OP_SYMBOL_REGISTRATION]: (inputs) => Symbol.for(inputs[0].description), - }; - - // Executes the given action. - // - // This will convert the inputs to concrete JavaScript values, then execute the operation with these inputs. - // Executing an action may change its guarding state: if a guarded action executes without raising an exception, - // it will be converted to an unguarded operation (as the guarding apears to not be needed). This way, we will - // ultimately end up emitting fewer try-catch (or equivalent) constructs in the final JavaScript code generated - // from these actions. - // - // Returns true if either the action succeeded without raising an exception or if the action is guarded, false otherwise. - // The output of the action is stored in |context.output| upon successful execution. - function execute(action, context) { - if (action === NO_ACTION) { - return true; + // Note: this code assumes that the common code from above has been included before. + + // + // List of all supported operations. Must be kept in sync with the ActionOperation enum. + // + const OP_CALL_FUNCTION = 'CALL_FUNCTION'; + const OP_CONSTRUCT = 'CONSTRUCT'; + const OP_CALL_METHOD = 'CALL_METHOD'; + const OP_CONSTRUCT_METHOD = 'CONSTRUCT_METHOD'; + const OP_GET_PROPERTY = 'GET_PROPERTY'; + const OP_SET_PROPERTY = 'SET_PROPERTY'; + const OP_DELETE_PROPERTY = 'DELETE_PROPERTY'; + + const OP_ADD = 'ADD'; + const OP_SUB = 'SUB'; + const OP_MUL = 'MUL'; + const OP_DIV = 'DIV'; + const OP_MOD = 'MOD'; + const OP_INC = 'INC'; + const OP_DEC = 'DEC'; + const OP_NEG = 'NEG'; + + const OP_LOGICAL_AND = 'LOGICAL_AND'; + const OP_LOGICAL_OR = 'LOGICAL_OR'; + const OP_LOGICAL_NOT = 'LOGICAL_NOT'; + const OP_NULL_COALESCE = 'NULL_COALESCE'; + + const OP_BITWISE_AND = 'BITWISE_AND'; + const OP_BITWISE_OR = 'BITWISE_OR'; + const OP_BITWISE_XOR = 'BITWISE_XOR'; + const OP_LEFT_SHIFT = 'LEFT_SHIFT'; + const OP_SIGNED_RIGHT_SHIFT = 'SIGNED_RIGHT_SHIFT'; + const OP_UNSIGNED_RIGHT_SHIFT = 'UNSIGNED_RIGHT_SHIFT'; + const OP_BITWISE_NOT = 'BITWISE_NOT'; + + const OP_COMPARE_EQUAL = 'COMPARE_EQUAL'; + const OP_COMPARE_STRICT_EQUAL = 'COMPARE_STRICT_EQUAL'; + const OP_COMPARE_NOT_EQUAL = 'COMPARE_NOT_EQUAL'; + const OP_COMPARE_STRICT_NOT_EQUAL = 'COMPARE_STRICT_NOT_EQUAL'; + const OP_COMPARE_GREATER_THAN = 'COMPARE_GREATER_THAN'; + const OP_COMPARE_LESS_THAN = 'COMPARE_LESS_THAN'; + const OP_COMPARE_GREATER_THAN_OR_EQUAL = 'COMPARE_GREATER_THAN_OR_EQUAL'; + const OP_COMPARE_LESS_THAN_OR_EQUAL = 'COMPARE_LESS_THAN_OR_EQUAL'; + const OP_TEST_IS_NAN = 'TEST_IS_NAN'; + const OP_TEST_IS_FINITE = 'TEST_IS_FINITE'; + + const OP_SYMBOL_REGISTRATION = 'SYMBOL_REGISTRATION'; + + // + // Action constructors. + // + function Action(operation, inputs) { + this.operation = operation; + this.inputs = inputs; + this.isGuarded = false; } - // Convert the action's inputs to the concrete JS values to use for executing the action. - let concreteInputs = EmptyArray(); - for (let i = 0; i < action.inputs.length; i++) { - let input = action.inputs[i]; - if (isArgumentInput(input)) { - let index = getArgumentInputIndex(input); - if (index >= context.arguments.length) throw "Invalid argument index: " + index; - push(concreteInputs, context.arguments[index]); - } else if (isSpecialInput(input)) { - let name = getSpecialInputName(input); - if (!hasOwnProperty(context.specialValues, name)) throw "Unknown special value: " + name; - push(concreteInputs, context.specialValues[name]); - } else if (isIntInput(input)) { - push(concreteInputs, getIntInputValue(input)); - } else if (isFloatInput(input)) { - push(concreteInputs, getFloatInputValue(input)); - } else if (isBigintInput(input)) { - // These need special handling because BigInts cannot be serialized into JSON, so are stored as strings. - push(concreteInputs, getBigintInputValue(input)); - } else if (isStringInput(input)) { - push(concreteInputs, getStringInputValue(input)); - } else { - throw "Unknown action input: " + stringify(input); - } + // A guarded action is an action that is allowed to raise an exception. + // + // These are for example used for by the ExplorationMutator for function/method call + // which may throw an exception if they aren't given the right arguments. In that case, + // we may still want to keep the function call so that it can be mutated further to + // hopefully eventually find the correct arguments. This is especially true if finding + // the right arguments reqires the ProbingMutator to install the right properties on an + // argument object, in which case the ExplorationMutator on its own would (likely) never + // be able to generate a valid call, and so the function/method may be missed entirely. + // + // If a guarded action succeeds (doesn't raise an exception), it will be converted to + // a regular action to limit the number of generated try-catch blocks. + function GuardedAction(operation, inputs) { + this.operation = operation; + this.inputs = inputs; + this.isGuarded = true; } - let handler = ACTION_HANDLERS[action.operation]; - if (isUndefined(handler)) throw "Unhandled operation " + action.operation; - - try { - context.output = handler(concreteInputs, context.currentThis); - // If the action succeeded, mark it as non-guarded so that we don't emit try-catch blocks for it later on. - // We could alternatively only do that if all executions succeeded, but it's probably fine to do it if at least one execution succeeded. - if (action.isGuarded) action.isGuarded = false; - } catch (e) { - return action.isGuarded; + // Special value to indicate that no action should be performed. + const NO_ACTION = null; + + // + // Action Input constructors. + // + // The inputs for actions are encoded as objects that specify both the type and the value of the input. They are basically enum values with associated values. + // These must be kept compatible with the Action.Input enum in RuntimeAssistedMutator.swift as they have to be encodable to/decodable from that enum. + // + function ArgumentInput(index) { + if (!isInteger(index)) throw "ArgumentInput index is not an integer: " + index; + return { argument: { index } }; + } + function SpecialInput(name) { + if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; + return { special: { name } }; } + function IntInput(value) { + if (!isInteger(value)) throw "IntInput value is not an integer: " + value; + return { int: { value } }; + } + function FloatInput(value) { + if (!isNumber(value) || !isFinite(value)) throw "FloatInput value is not a (finite) number: " + value; + return { float: { value } }; + } + function BigintInput(value) { + if (!isBigint(value)) throw "BigintInput value is not a bigint: " + value; + // Bigints can't be serialized by JSON.stringify, so store them as strings instead. + return { bigint: { value: bigintToString(value) } }; + } + function StringInput(value) { + if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; + return { string: { value } }; + } + + // Type checkers for Input objects. We use these instead of for example 'instanceof' since we allow Input + // objects to be decoded from JSON, in which case they will not have the right .constructor property. + function isArgumentInput(input) { return hasOwnProperty(input, 'argument'); } + function isSpecialInput(input) { return hasOwnProperty(input, 'special'); } + function isIntInput(input) { return hasOwnProperty(input, 'int'); } + function isFloatInput(input) { return hasOwnProperty(input, 'float'); } + function isBigintInput(input) { return hasOwnProperty(input, 'bigint'); } + function isStringInput(input) { return hasOwnProperty(input, 'string'); } + + // Helper routines to extract the associated values from Input objects. + function getArgumentInputIndex(input) { return input.argument.index; } + function getSpecialInputName(input) { return input.special.name; } + function getIntInputValue(input) { return input.int.value; } + function getFloatInputValue(input) { return input.float.value; } + function getBigintInputValue(input) { return BigIntConstructor(input.bigint.value); } + function getStringInputValue(input) { return input.string.value; } + + // Handlers for executing actions. + // These will receive the array of concrete inputs (i.e. JavaScript values) as first parameter and the current value of |this| as second parameter (which can be ignored if not needed). + const ACTION_HANDLERS = { + [OP_CALL_FUNCTION]: (inputs, currentThis) => { let f = shift(inputs); return apply(f, currentThis, inputs); }, + [OP_CONSTRUCT]: (inputs) => { let c = shift(inputs); return construct(c, inputs); }, + [OP_CALL_METHOD]: (inputs) => { let o = shift(inputs); let m = shift(inputs); return apply(o[m], o, inputs); }, + [OP_CONSTRUCT_METHOD]: (v, inputs) => { let o = shift(inputs); let m = shift(inputs); return construct(o[m], inputs); }, + [OP_GET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return o[p]; }, + [OP_SET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; let v = inputs[2]; o[p] = v; }, + [OP_DELETE_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return delete o[p]; }, + [OP_ADD]: (inputs) => inputs[0] + inputs[1], + [OP_SUB]: (inputs) => inputs[0] - inputs[1], + [OP_MUL]: (inputs) => inputs[0] * inputs[1], + [OP_DIV]: (inputs) => inputs[0] / inputs[1], + [OP_MOD]: (inputs) => inputs[0] % inputs[1], + [OP_INC]: (inputs) => inputs[0]++, + [OP_DEC]: (inputs) => inputs[0]--, + [OP_NEG]: (inputs) => -inputs[0], + [OP_LOGICAL_AND]: (inputs) => inputs[0] && inputs[1], + [OP_LOGICAL_OR]: (inputs) => inputs[0] || inputs[1], + [OP_LOGICAL_NOT]: (inputs) => !inputs[0], + [OP_NULL_COALESCE]: (inputs) => inputs[0] ?? inputs[1], + [OP_BITWISE_AND]: (inputs) => inputs[0] & inputs[1], + [OP_BITWISE_OR]: (inputs) => inputs[0] | inputs[1], + [OP_BITWISE_XOR]: (inputs) => inputs[0] ^ inputs[1], + [OP_LEFT_SHIFT]: (inputs) => inputs[0] << inputs[1], + [OP_SIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >> inputs[1], + [OP_UNSIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >>> inputs[1], + [OP_BITWISE_NOT]: (inputs) => ~inputs[0], + [OP_COMPARE_EQUAL]: (inputs) => inputs[0] == inputs[1], + [OP_COMPARE_STRICT_EQUAL]: (inputs) => inputs[0] === inputs[1], + [OP_COMPARE_NOT_EQUAL]: (inputs) => inputs[0] != inputs[1], + [OP_COMPARE_STRICT_NOT_EQUAL]: (inputs) => inputs[0] !== inputs[1], + [OP_COMPARE_GREATER_THAN]: (inputs) => inputs[0] > inputs[1], + [OP_COMPARE_LESS_THAN]: (inputs) => inputs[0] < inputs[1], + [OP_COMPARE_GREATER_THAN_OR_EQUAL]: (inputs) => inputs[0] >= inputs[1], + [OP_COMPARE_LESS_THAN_OR_EQUAL]: (inputs) => inputs[0] <= inputs[1], + [OP_TEST_IS_NAN]: (inputs) => Number.isNaN(inputs[0]), + [OP_TEST_IS_FINITE]: (inputs) => Number.isFinite(inputs[0]), + [OP_SYMBOL_REGISTRATION]: (inputs) => Symbol.for(inputs[0].description), + }; - return true; - } - """ + // Executes the given action. + // + // This will convert the inputs to concrete JavaScript values, then execute the operation with these inputs. + // Executing an action may change its guarding state: if a guarded action executes without raising an exception, + // it will be converted to an unguarded operation (as the guarding apears to not be needed). This way, we will + // ultimately end up emitting fewer try-catch (or equivalent) constructs in the final JavaScript code generated + // from these actions. + // + // Returns true if either the action succeeded without raising an exception or if the action is guarded, false otherwise. + // The output of the action is stored in |context.output| upon successful execution. + function execute(action, context) { + if (action === NO_ACTION) { + return true; + } + + // Convert the action's inputs to the concrete JS values to use for executing the action. + let concreteInputs = EmptyArray(); + for (let i = 0; i < action.inputs.length; i++) { + let input = action.inputs[i]; + if (isArgumentInput(input)) { + let index = getArgumentInputIndex(input); + if (index >= context.arguments.length) throw "Invalid argument index: " + index; + push(concreteInputs, context.arguments[index]); + } else if (isSpecialInput(input)) { + let name = getSpecialInputName(input); + if (!hasOwnProperty(context.specialValues, name)) throw "Unknown special value: " + name; + push(concreteInputs, context.specialValues[name]); + } else if (isIntInput(input)) { + push(concreteInputs, getIntInputValue(input)); + } else if (isFloatInput(input)) { + push(concreteInputs, getFloatInputValue(input)); + } else if (isBigintInput(input)) { + // These need special handling because BigInts cannot be serialized into JSON, so are stored as strings. + push(concreteInputs, getBigintInputValue(input)); + } else if (isStringInput(input)) { + push(concreteInputs, getStringInputValue(input)); + } else { + throw "Unknown action input: " + stringify(input); + } + } + + let handler = ACTION_HANDLERS[action.operation]; + if (isUndefined(handler)) throw "Unhandled operation " + action.operation; + + try { + context.output = handler(concreteInputs, context.currentThis); + // If the action succeeded, mark it as non-guarded so that we don't emit try-catch blocks for it later on. + // We could alternatively only do that if all executions succeeded, but it's probably fine to do it if at least one execution succeeded. + if (action.isGuarded) action.isGuarded = false; + } catch (e) { + return action.isGuarded; + } + + return true; + } + """ } diff --git a/Sources/Fuzzilli/Lifting/ScriptWriter.swift b/Sources/Fuzzilli/Lifting/ScriptWriter.swift index 8b53a9075..f9c029856 100644 --- a/Sources/Fuzzilli/Lifting/ScriptWriter.swift +++ b/Sources/Fuzzilli/Lifting/ScriptWriter.swift @@ -36,7 +36,10 @@ struct ScriptWriter { /// Current line, used when including line numbers in the output. public private(set) var currentLineNumber = 0 - public init (stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, initialIndentionLevel: Int = 0, maxLineLength: Int = Int.max) { + public init( + stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, + initialIndentionLevel: Int = 0, maxLineLength: Int = Int.max + ) { self.indent = String(repeating: " ", count: indent) self.currentIndention = String(repeating: " ", count: indent * initialIndentionLevel) self.stripComments = stripComments @@ -59,7 +62,8 @@ struct ScriptWriter { while line.count > splitAt { var lineToPrint = line.prefix(splitAt + 1) if let spaceIndex = lineToPrint.lastIndex(of: " "), - spaceIndex != lineToPrint.startIndex { + spaceIndex != lineToPrint.startIndex + { // Only print the line if it contains non-space characters trimming all trailing // spaces. lineToPrint = lineToPrint.prefix(upTo: spaceIndex) @@ -71,7 +75,7 @@ struct ScriptWriter { emitImpl(line.prefix(splitAt)) line = line.suffix(line.count - splitAt) } - line = line.suffix(from: line.firstIndex {$0 != " "} ?? line.endIndex) + line = line.suffix(from: line.firstIndex { $0 != " " } ?? line.endIndex) } if !line.isEmpty { emitImpl(line) @@ -94,7 +98,9 @@ struct ScriptWriter { for line in block.split(separator: "\n", omittingEmptySubsequences: false) { if stripComments { let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) - if trimmedLine.hasPrefix("//") || (trimmedLine.hasPrefix("/*") && trimmedLine.hasSuffix("*/")) { + if trimmedLine.hasPrefix("//") + || (trimmedLine.hasPrefix("/*") && trimmedLine.hasSuffix("*/")) + { continue } } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index d57adaf38..13f91758d 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - import Foundation /// Represents the type identifiers for each code section according to the wasm @@ -43,18 +42,18 @@ private enum Prefix: UInt8 { // This maps ILTypes to their respective binary encoding. private let ILTypeMapping: [ILType: Data] = [ - .wasmi32 : Data([0x7F]), - .wasmi64 : Data([0x7E]), - .wasmf32 : Data([0x7D]), - .wasmf64 : Data([0x7C]), + .wasmi32: Data([0x7F]), + .wasmi64: Data([0x7E]), + .wasmf32: Data([0x7D]), + .wasmf64: Data([0x7C]), .wasmSimd128: Data([0x7B]), .wasmPackedI8: Data([0x78]), .wasmPackedI16: Data([0x77]), - .bigint : Data([0x7E]), // Maps to .wasmi64 - .jsAnything: Data([0x6F]), // Maps to .wasmExternRef - .integer: Data([0x7F]), // Maps to .wasmi32 - .number: Data([0x7D]) // Maps to .wasmf32 + .bigint: Data([0x7E]), // Maps to .wasmi64 + .jsAnything: Data([0x6F]), // Maps to .wasmExternRef + .integer: Data([0x7F]), // Maps to .wasmi32 + .number: Data([0x7D]), // Maps to .wasmf32 ] /// This is the main compiler for Wasm instructions. @@ -118,7 +117,7 @@ public class WasmLifter { // This can further be filtered for only e.g. tag imports by doing this. // `exports.compactMap({$0.getImport()}).filter({$0.type.isFunction})` - var isFunction : Bool { + var isFunction: Bool { if case .function(_) = self { return true } else { @@ -126,7 +125,7 @@ public class WasmLifter { } } - var isTable : Bool { + var isTable: Bool { if case .table(_) = self { return true } else { @@ -134,7 +133,7 @@ public class WasmLifter { } } - var isMemory : Bool { + var isMemory: Bool { if case .memory(_) = self { return true } else { @@ -142,7 +141,7 @@ public class WasmLifter { } } - var isGlobal : Bool { + var isGlobal: Bool { if case .global(_) = self { return true } else { @@ -150,7 +149,7 @@ public class WasmLifter { } } - var isTag : Bool { + var isTag: Bool { if case .tag(_) = self { return true } else { @@ -158,7 +157,7 @@ public class WasmLifter { } } - var isSuspendingObject : Bool { + var isSuspendingObject: Bool { if case .suspendingObject = self { return true } else { @@ -167,7 +166,7 @@ public class WasmLifter { } func getImport() -> (type: Self, variable: Variable, signature: WasmSignature?)? { - if case let .import(export, variable, signature) = self { + if case .import(let export, let variable, let signature) = self { return (export, variable, signature) } return nil @@ -176,13 +175,13 @@ public class WasmLifter { func getDefInstr() -> Instruction? { switch self { case .function(_), - .import(_, _, _), - .suspendingObject: + .import(_, _, _), + .suspendingObject: return nil case .global(let instr), - .table(let instr), - .memory(let instr), - .tag(let instr): + .table(let instr), + .memory(let instr), + .tag(let instr): return instr! } } @@ -190,8 +189,8 @@ public class WasmLifter { func groupName() -> String { switch self { case .function, - .import, - .suspendingObject: + .import, + .suspendingObject: // Functions and imports don't have group names, this is used for getting imports of that type. fatalError("unreachable") case .table: @@ -208,7 +207,7 @@ public class WasmLifter { func exportName(forIdx idx: Int) -> String { return switch self { case .function, - .suspendingObject: + .suspendingObject: WasmLifter.nameOfFunction(idx) case .table: WasmLifter.nameOfTable(idx) @@ -226,7 +225,7 @@ public class WasmLifter { func exportTypeByte() -> Int { switch self { case .function, - .suspendingObject: + .suspendingObject: return 0x0 case .table: return 0x1 @@ -290,20 +289,20 @@ public class WasmLifter { private var dataSegments: [Instruction] = [] private var elementSegments: [Instruction] = [] -// // The tags associated with this module. -// private var tags: VariableMap<[ILType]> = VariableMap() + // // The tags associated with this module. + // private var tags: VariableMap<[ILType]> = VariableMap() private var typeGroups: Set = [] - private var typeDescToIndex : [WasmTypeDescription:Int] = [:] + private var typeDescToIndex: [WasmTypeDescription: Int] = [:] private var userDefinedTypesCount = 0 // The function index space private var functionIdxBase = 0 // The signature index space. - private var signatures : [WasmSignature] = [] - private var signatureIndexMap : [WasmSignature: Int] = [:] + private var signatures: [WasmSignature] = [] + private var signatureIndexMap: [WasmSignature: Int] = [:] // This tracks in which order we have seen globals, this can probably be unified with the .globals and .imports properties, as they should match in their keys. private var globalOrder: [Variable] = [] @@ -342,9 +341,7 @@ public class WasmLifter { private var writer = WasmExprWriter() var isEmpty: Bool { - return instructionBuffer.isEmpty && - self.bytecode.isEmpty && - self.exports.isEmpty + return instructionBuffer.isEmpty && self.bytecode.isEmpty && self.exports.isEmpty } // TODO: maybe we can do some analysis based on blocks. @@ -374,7 +371,10 @@ public class WasmLifter { public var labelBranchDepthMapping: VariableMap = VariableMap() // Expects the withArguments array to contain the variables of the innerOutputs, they should map directly to the local indices. - init(_ signature: WasmSignature, _ code: Data, for lifter: WasmLifter, withArguments arguments: [Variable]) { + init( + _ signature: WasmSignature, _ code: Data, for lifter: WasmLifter, + withArguments arguments: [Variable] + ) { // Infer the first few locals from this signature. self.signature = signature self.code = code @@ -385,7 +385,9 @@ public class WasmLifter { for (idx, argVar) in arguments.dropFirst().enumerated() { self.localsInfo.append((argVar, signature.parameterTypes[idx])) // Emit the expressions for the parameters such that we can accesss them if we need them. - self.lifter!.writer.addExpr(for: argVar, bytecode: Data([0x20]) + Leb128.unsignedEncode(self.localsInfo.count - 1)) + self.lifter!.writer.addExpr( + for: argVar, + bytecode: Data([0x20]) + Leb128.unsignedEncode(self.localsInfo.count - 1)) } } @@ -402,7 +404,7 @@ public class WasmLifter { } func isLocal(_ variable: Variable) -> Bool { - self.localsInfo.contains(where: {$0.0 == variable}) + self.localsInfo.contains(where: { $0.0 == variable }) } func getStackSlot(for variable: Variable) -> Int? { @@ -469,14 +471,13 @@ public class WasmLifter { // All functions should have associated byte code at this point. // - // // Step 3: Lift the whole module and put everything together. // if verbose { print("Got the following functions") - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { print("\(String(describing: functionInfo))") } } @@ -532,19 +533,19 @@ public class WasmLifter { // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/wasm/wasm-constants.h?q=symbol:ValueTypeCode let sharedFlagPrefix: [UInt8] = heapTypeInfo.shared ? [0x65] : [] let opCode: UInt8 = - switch (heapTypeInfo.heapType) { - case .WasmExtern: 0x6F - case .WasmFunc: 0x70 - case .WasmAny: 0x6E - case .WasmEq: 0x6D - case .WasmI31: 0x6C - case .WasmStruct: 0x6B - case .WasmArray: 0x6A - case .WasmExn: 0x69 - case .WasmNone: 0x71 - case .WasmNoExtern: 0x72 - case .WasmNoFunc: 0x73 - case .WasmNoExn: 0x74 + switch heapTypeInfo.heapType { + case .WasmExtern: 0x6F + case .WasmFunc: 0x70 + case .WasmAny: 0x6E + case .WasmEq: 0x6D + case .WasmI31: 0x6C + case .WasmStruct: 0x6B + case .WasmArray: 0x6A + case .WasmExn: 0x69 + case .WasmNone: 0x71 + case .WasmNoExtern: 0x72 + case .WasmNoFunc: 0x73 + case .WasmNoExn: 0x74 } return Data(sharedFlagPrefix + [opCode]) } @@ -585,7 +586,9 @@ public class WasmLifter { } // Helper method in cases we have either abstract type represented by ILType or an index type Variable - private func encodeReferenceType(_ refType: WasmReferenceType, instr: Instruction, typeInput: Int) throws -> Data { + private func encodeReferenceType( + _ refType: WasmReferenceType, instr: Instruction, typeInput: Int + ) throws -> Data { switch refType.kind { case .Abstract(let heapTypeInfo): return encodeAbstractHeapType(heapTypeInfo) @@ -629,7 +632,7 @@ public class WasmLifter { } // Special handling for defined functions - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { registerSignature(functionInfo!.signature) } @@ -711,14 +714,16 @@ public class WasmLifter { temp += Leb128.unsignedEncode(self.exports.count { $0.getImport() != nil }) // Build the import components of this vector that consist of mod:name, nm:name, and d:importdesc - for (idx, (_, importVariable, signature)) in self.exports.compactMap({ $0.getImport() }).enumerated() { + for (idx, (_, importVariable, signature)) in self.exports.compactMap({ $0.getImport() }) + .enumerated() + { if verbose { print(importVariable) } // Append the name as a vector temp += Leb128.unsignedEncode("imports".count) temp += "imports".data(using: .utf8)! - var importName : String + var importName: String importName = "import_\(idx)_\(importVariable)" temp += Leb128.unsignedEncode(importName.count) temp += importName.data(using: .utf8)! @@ -739,7 +744,9 @@ public class WasmLifter { temp += Data([0x2]) let mem = type.wasmMemoryType! - let limits_byte: UInt8 = (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0); + let limits_byte: UInt8 = + (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) + | (mem.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(mem.limits.min)) @@ -755,7 +762,8 @@ public class WasmLifter { let table = type.wasmTableType! temp += try encodeType(table.elementType) - let limits_byte: UInt8 = (table.isTable64 ? 4 : 0) | (table.limits.max != nil ? 1 : 0) + let limits_byte: UInt8 = + (table.isTable64 ? 4 : 0) | (table.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(table.limits.min)) @@ -772,7 +780,7 @@ public class WasmLifter { temp += mutability ? [0x1] : [0x0] continue } - if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { + if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { temp += [0x4, 0x0] + Leb128.unsignedEncode(try getSignatureIndex(signature!)) continue } @@ -803,7 +811,7 @@ public class WasmLifter { // TODO(cffsmith): functions can share type indices. This could be an optimization later on. var temp = Leb128.unsignedEncode(functionCount) - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { temp.append(Leb128.unsignedEncode(try getSignatureIndex(functionInfo!.signature))) } @@ -829,7 +837,7 @@ public class WasmLifter { var temp = Leb128.unsignedEncode(tableCount) - for case let .table(instruction) in self.exports { + for case .table(let instruction) in self.exports { let op = instruction!.op as! WasmDefineTable let elementType = op.elementType let minSize = op.limits.min @@ -865,20 +873,20 @@ public class WasmLifter { // - constant starting index. private func buildElementSection() throws { let numDefinedTablesWithEntries = self.exports.count { - if case let .table(instruction) = $0 { + if case .table(let instruction) = $0 { return !(instruction!.op as! WasmDefineTable).definedEntries.isEmpty } else { return false } } - if numDefinedTablesWithEntries == 0 && elementSegments.count == 0 { return } + if numDefinedTablesWithEntries == 0 && elementSegments.count == 0 { return } self.bytecode += [WasmSection.element.rawValue] - var temp = Data(); + var temp = Data() // Element segment count. - temp += Leb128.unsignedEncode(numDefinedTablesWithEntries + elementSegments.count); + temp += Leb128.unsignedEncode(numDefinedTablesWithEntries + elementSegments.count) // Passive element segments. They go first so that their indexes start with 0. for instruction in self.elementSegments { @@ -897,7 +905,7 @@ public class WasmLifter { } // Active element segments - for case let .table(instruction) in self.exports { + for case .table(let instruction) in self.exports { let table = instruction!.op as! WasmDefineTable let definedEntries = table.definedEntries assert(definedEntries.count == instruction!.inputs.count) @@ -945,7 +953,7 @@ public class WasmLifter { let functions = self.exports.filter({ $0.isFunction }) - let importedFunctionCount = self.exports.compactMap({$0.getImport()}).count { + let importedFunctionCount = self.exports.compactMap({ $0.getImport() }).count { $0.type.isFunction } @@ -965,8 +973,11 @@ public class WasmLifter { var funcTemp = Data() // TODO: this should be encapsulated more nicely. There should be an interface that gets the locals without the parameters. As this is currently mainly used to get the slots info. // Encode number of locals - funcTemp += Leb128.unsignedEncode(functionInfo!.localsInfo.count - functionInfo!.signature.parameterTypes.count) - for (_, type) in functionInfo!.localsInfo[functionInfo!.signature.parameterTypes.count...] { + funcTemp += Leb128.unsignedEncode( + functionInfo!.localsInfo.count - functionInfo!.signature.parameterTypes.count) + for (_, type) in functionInfo!.localsInfo[ + functionInfo!.signature.parameterTypes.count...] + { // Encode the locals funcTemp += Leb128.unsignedEncode(1) funcTemp += try encodeType(type) @@ -985,7 +996,8 @@ public class WasmLifter { // The function entry is the function index, followed by the counts of branch hints // for this function and then the bytes containing the actual branch hints. let functionIndex = defIndex + importedFunctionCount - let hintsEncoded = Leb128.unsignedEncode(functionIndex) + let hintsEncoded = + Leb128.unsignedEncode(functionIndex) + Leb128.unsignedEncode(functionInfo!.branchHints.count) + functionInfo!.branchHints.map { // Each branch hint is the instruction offset starting from the locals @@ -1001,7 +1013,8 @@ public class WasmLifter { if !functionBranchHints.isEmpty { self.bytecode += [WasmSection.custom.rawValue] let name = "metadata.code.branch_hint" - let sectionContent = Leb128.unsignedEncode(name.count) + Data(name.data(using: .ascii)!) + let sectionContent = + Leb128.unsignedEncode(name.count) + Data(name.data(using: .ascii)!) + Leb128.unsignedEncode(functionBranchHints.count) + functionBranchHints.joined() self.bytecode.append(Leb128.unsignedEncode(sectionContent.count)) self.bytecode.append(sectionContent) @@ -1032,7 +1045,7 @@ public class WasmLifter { for instruction in self.dataSegments { let segment = (instruction.op as! WasmDefineDataSegment).segment - temp += Data([0x01]) // mode = passive + temp += Data([0x01]) // mode = passive temp += Leb128.unsignedEncode(segment.count) temp += Data(segment) } @@ -1076,7 +1089,7 @@ public class WasmLifter { var temp = Leb128.unsignedEncode(globalCount) // TODO: in the future this should maybe be a context that allows instructions? Such that we can fuzz this expression as well? - for case let .global(instruction) in self.exports { + for case .global(let instruction) in self.exports { let definition = instruction!.op as! WasmDefineGlobal let global = definition.wasmGlobal @@ -1104,7 +1117,7 @@ public class WasmLifter { temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref()) + Data([0x0B]) continue case .refFunc(_), - .imported(_): + .imported(_): fatalError("unreachable") } temp += try lift(temporaryInstruction!) @@ -1132,12 +1145,13 @@ public class WasmLifter { self.bytecode += [WasmSection.memory.rawValue] var temp = Leb128.unsignedEncode(memoryCount) - for case let .memory(instruction) in self.exports { + for case .memory(let instruction) in self.exports { let type = typer.type(of: instruction!.output) assert(type.isWasmMemoryType) let mem = type.wasmMemoryType! - let limits_byte: UInt8 = (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0); + let limits_byte: UInt8 = + (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(mem.limits.min)) @@ -1159,7 +1173,7 @@ public class WasmLifter { private func buildTagSection() throws { if self.exports.count(where: { $0.isTag }) == 0 { - return // Skip the whole section. + return // Skip the whole section. } self.bytecode.append(WasmSection.tag.rawValue) @@ -1167,7 +1181,7 @@ public class WasmLifter { section += Leb128.unsignedEncode(self.exports.count { $0.isTag }) - for case let .tag(instr) in self.exports { + for case .tag(let instr) in self.exports { let signatureDesc = typer.getTypeDescription(of: instr!.input(0)) section.append(0) section.append(Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) @@ -1204,11 +1218,12 @@ public class WasmLifter { temp += Leb128.unsignedEncode(name.count) temp += name.data(using: .utf8)! // Add the base, as our exports start after the imports. This variable needs to be incremented in the `buildImportSection` function. - temp += Leb128.unsignedEncode(export.exportTypeByte()) + Leb128.unsignedEncode(idx + offset) + temp += + Leb128.unsignedEncode(export.exportTypeByte()) + Leb128.unsignedEncode(idx + offset) } // The predicate is used to filter for only a specific type of import. - let reexportAndExport: ((Export) -> Bool) -> () = { predicate in + let reexportAndExport: ((Export) -> Bool) -> Void = { predicate in let imported = self.exports.filter({ $0.getImport() != nil && predicate($0.getImport()!.type) }) @@ -1266,41 +1281,51 @@ public class WasmLifter { switch instr.op.opcode { case .wasmBeginBlock(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginIf(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginElse(_): // Note: We need to subtract one because the begin else block closes the if block before opening the else block! - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmBeginTryTable(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginTry(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginTryDelegate(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginLoop(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginCatch(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(1)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(1)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmBeginCatchAll(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmCallIndirect(let op): @@ -1315,26 +1340,31 @@ public class WasmLifter { break case .beginWasmFunction(_): let signature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature - let functionInfo = FunctionInfo(signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) + let functionInfo = FunctionInfo( + signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) self.exports.append(.function(functionInfo)) // Set the current active function as we are *actively* in it. currentFunction = functionInfo - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth case .endWasmFunction(_): currentFunction!.outputVariable = instr.output return true case .wasmDefineGlobal(_): - assert(self.exports.contains(where: { - $0.isGlobal && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isGlobal && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineTable(_): - assert(self.exports.contains(where: { - $0.isTable && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isTable && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineMemory(_): - assert(self.exports.contains(where: { - $0.isMemory && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isMemory && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineDataSegment(_): self.dataSegments.append(instr) case .wasmDefineElementSegment(_): @@ -1344,16 +1374,18 @@ public class WasmLifter { case .wasmThrow(_): return true case .wasmDefineTag(_): - assert(self.exports.contains(where: { - if case .tag(let i) = $0 { - return i!.output == instr.output - } else { - return false - } - })) - assert(self.exports.contains(where: { - $0.isTag && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + if case .tag(let i) = $0 { + return i!.output == instr.output + } else { + return false + } + })) + assert( + self.exports.contains(where: { + $0.isTag && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineAdHocModuleSignatureType(_): break default: @@ -1404,18 +1436,23 @@ public class WasmLifter { // reassigns. Similarly, the end of a function doesn't spill anything. // WasmDefineAdHocSignatureType isn't a wasm instruction and therefore also doesn't have any // Wasm stack inputs. - if instr.op is WasmReassign || instr.op is EndWasmFunction || instr.op is WasmDefineAdHocSignatureType { + if instr.op is WasmReassign || instr.op is EndWasmFunction + || instr.op is WasmDefineAdHocSignatureType + { return } // If we have an output, make sure we store it on the stack as this is a "complex" instruction, i.e. has inputs and outputs. if instr.numOutputs > 0 { - assert(instr.outputs.allSatisfy {!typer.type(of: $0).Is(.anyLabel)}) + assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyLabel) }) for output in instr.outputs.reversed() { // Also spill the instruction currentFunction!.spillLocal(forVariable: output) // Add the corresponding stack load as an expression, this adds the number of arguments, as output vars always live after the function arguments. - self.writer.addExpr(for: output, bytecode: Data([0x20]) + Leb128.unsignedEncode(currentFunction!.localsInfo.count - 1)) + self.writer.addExpr( + for: output, + bytecode: Data([0x20]) + + Leb128.unsignedEncode(currentFunction!.localsInfo.count - 1)) } } @@ -1460,7 +1497,6 @@ public class WasmLifter { return } - // Now check for generic imports that we can just import as is without using a signature. if !imports.contains(where: { // if we have a signature, we need to make sure that create a new import with that signature. @@ -1486,7 +1522,8 @@ public class WasmLifter { } // Add typegroups and their dependencies. if typeGroups.insert(typeDesc.typeGroupIndex).inserted { - typeGroups.formUnion(typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) + typeGroups.formUnion( + typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) } } @@ -1504,19 +1541,28 @@ public class WasmLifter { throw WasmLifter.CompileError.missingTypeInformation } // TODO: This now uses the typer here but the op also carries this information? - importIfNeeded(.import(type: .tag(nil), variable: input, signature: inputType.wasmTagType!.parameters => [])) + importIfNeeded( + .import( + type: .tag(nil), variable: input, + signature: inputType.wasmTagType!.parameters => [])) } // Special handling for functions, we only expect them in WasmJSCalls, and WasmDefineTable instructions right now. // We can treat the suspendingObjects as function imports. - if inputType.Is(.function()) || inputType.Is(.object(ofGroup: "WasmSuspendingObject")) { + if inputType.Is(.function()) + || inputType.Is(.object(ofGroup: "WasmSuspendingObject")) + { if case .wasmJsCall(_) = instr.op.opcode { - let wasmSignature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature - importIfNeeded(.import(type: .function(nil), variable: input, signature: wasmSignature)) + let wasmSignature = typer.type(of: instr.input(0)) + .wasmFunctionSignatureDefSignature + importIfNeeded( + .import(type: .function(nil), variable: input, signature: wasmSignature) + ) } else if case .wasmDefineTable(let op) = instr.op.opcode { // Find the signature in the defined entries let sig = op.definedEntries[idx].signature - importIfNeeded(.import(type: .function(nil), variable: input, signature: sig)) + importIfNeeded( + .import(type: .function(nil), variable: input, signature: sig)) } else { // This instruction has likely expected some .object() of a specific group, as this variable can originate from outside wasm, it might have been reassigned to. Which means we will enter this path. // Therefore we need to bail. @@ -1536,7 +1582,10 @@ public class WasmLifter { for (value, definedEntry) in zip(instr.inputs, tableDef.definedEntries) { if !typer.type(of: value).Is(.wasmFunctionDef()) { // Check if we need to import the inputs. - importIfNeeded(.import(type: .function(nil), variable: value, signature: definedEntry.signature)) + importIfNeeded( + .import( + type: .function(nil), variable: value, + signature: definedEntry.signature)) } } } @@ -1600,7 +1649,7 @@ public class WasmLifter { }) // Now get the index in this "import space" - if let idx = imports.firstIndex(where: { + if let idx = imports.firstIndex(where: { $0.variable == input }) { return idx @@ -1624,11 +1673,11 @@ public class WasmLifter { } func resolveDataSegmentIdx(for input: Variable) -> Int { - dataSegments.firstIndex {$0.output == input}! + dataSegments.firstIndex { $0.output == input }! } func resolveElementSegmentIdx(for input: Variable) -> Int { - elementSegments.firstIndex {$0.output == input}! + elementSegments.firstIndex { $0.output == input }! } // The memory immediate argument, which encodes the alignment and memory index. @@ -1637,12 +1686,13 @@ public class WasmLifter { // Memory zero: `[align]`. // Multi-memory: `[align | 0x40] + [mem_idx]`. private func alignmentAndMemoryBytes(_ memory: Variable, alignment: Int64 = 1) throws -> Data { - assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be a power of two") + assert( + alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be a power of two") let memoryIdx = try resolveIdx(ofType: .memory, for: memory) - let alignmentLog2 = alignment.trailingZeroBitCount - assert(alignmentLog2 < 0x40, "Alignment \(alignment) is too large for multi-memory encoding") + assert( + alignmentLog2 < 0x40, "Alignment \(alignment) is too large for multi-memory encoding") if memoryIdx == 0 { return Leb128.unsignedEncode(alignmentLog2) @@ -1832,57 +1882,71 @@ public class WasmLifter { return Data([0x24]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: input)) case .wasmTableGet(_): let tableRef = wasmInstruction.input(0) - return Data([0x25]) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x25]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableSet(_): let tableRef = wasmInstruction.input(0) - return Data([0x26]) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x26]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableSize(_): let tableRef = wasmInstruction.input(0) // Value 0x10 is table.size opcode - return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x10) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x10) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableGrow(_): let tableRef = wasmInstruction.input(0) // Value 0x0f is table.grow opcode - return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x0f) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x0f) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmCallIndirect(let op): let tableRef = wasmInstruction.input(0) let sigIndex = try getSignatureIndex(op.signature) - return Data([0x11]) + Leb128.unsignedEncode(sigIndex) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x11]) + Leb128.unsignedEncode(sigIndex) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmCallDirect(_): let functionRef = wasmInstruction.input(0) - return Data([0x10]) + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) + return Data([0x10]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) case .wasmReturnCallDirect(_): let functionRef = wasmInstruction.input(0) - return Data([0x12]) + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) + return Data([0x12]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) case .wasmReturnCallIndirect(let op): let tableRef = wasmInstruction.input(0) let sigIndex = try getSignatureIndex(op.signature) - return Data([0x13]) + Leb128.unsignedEncode(sigIndex) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x13]) + Leb128.unsignedEncode(sigIndex) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmMemoryLoad(let op): let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - return Data([op.loadType.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + return Data([op.loadType.rawValue]) + alignAndMemory + + Leb128.signedEncode(Int(op.staticOffset)) case .wasmMemoryStore(let op): let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - let opCode = Data(op.storeType != .S128StoreMem - ? [op.storeType.rawValue] - : [Prefix.Simd.rawValue, op.storeType.rawValue]) + let opCode = Data( + op.storeType != .S128StoreMem + ? [op.storeType.rawValue] + : [Prefix.Simd.rawValue, op.storeType.rawValue]) return opCode + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) case .wasmAtomicLoad(let op): let opcode = [Prefix.Atomic.rawValue, op.loadType.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.loadType.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.loadType.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicStore(let op): let opcode = [Prefix.Atomic.rawValue, op.storeType.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.storeType.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.storeType.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicRMW(let op): let opcode = [Prefix.Atomic.rawValue, op.op.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.op.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.op.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicCmpxchg(let op): let opcode = [Prefix.Atomic.rawValue, op.op.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.op.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.op.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmMemorySize(_): let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) @@ -1893,14 +1957,16 @@ public class WasmLifter { case .wasmMemoryCopy(_): let dstMemIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) let srcMemIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0A]) + Leb128.unsignedEncode(dstMemIdx) + Leb128.unsignedEncode(srcMemIdx) + return Data([0xFC, 0x0A]) + Leb128.unsignedEncode(dstMemIdx) + + Leb128.unsignedEncode(srcMemIdx) case .wasmMemoryFill(_): let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) return Data([0xFC, 0x0B]) + Leb128.unsignedEncode(memoryIdx) case .wasmMemoryInit(_): let dataSegmentIdx = resolveDataSegmentIdx(for: wasmInstruction.input(0)) let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(1)) - return Data([0xFC, 0x08]) + Leb128.unsignedEncode(dataSegmentIdx) + Leb128.unsignedEncode(memoryIdx) + return Data([0xFC, 0x08]) + Leb128.unsignedEncode(dataSegmentIdx) + + Leb128.unsignedEncode(memoryIdx) case .wasmDropDataSegment(_): let dataSegmentIdx = resolveDataSegmentIdx(for: wasmInstruction.input(0)) return Data([0xFC, 0x09]) + Leb128.unsignedEncode(dataSegmentIdx) @@ -1910,14 +1976,17 @@ public class WasmLifter { case .wasmTableInit(_): let elementSegmentIdx = resolveElementSegmentIdx(for: wasmInstruction.input(0)) let tableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0c]) + Leb128.unsignedEncode(elementSegmentIdx) + Leb128.unsignedEncode(tableIdx) + return Data([0xFC, 0x0c]) + Leb128.unsignedEncode(elementSegmentIdx) + + Leb128.unsignedEncode(tableIdx) case .wasmTableCopy(_): let dstTableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(0)) let srcTableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0e]) + Leb128.unsignedEncode(dstTableIdx) + Leb128.unsignedEncode(srcTableIdx) + return Data([0xFC, 0x0e]) + Leb128.unsignedEncode(dstTableIdx) + + Leb128.unsignedEncode(srcTableIdx) case .wasmJsCall(_): // We filter first, such that we get the index of functions only. - let wasmSignature = typer.type(of: wasmInstruction.input(0)).wasmFunctionSignatureDefSignature + let wasmSignature = typer.type(of: wasmInstruction.input(0)) + .wasmFunctionSignatureDefSignature // This has somewhat special handling as we might have multiple imports for this variable, we also need to get the right index that matches that signature that we expect here. // TODO(cffsmith): consider adding that signature matching feature to resolveIdx. @@ -1928,7 +1997,8 @@ public class WasmLifter { return false } }).firstIndex(where: { - wasmInstruction.input(1) == $0.getImport()!.variable && wasmSignature == $0.getImport()!.signature + wasmInstruction.input(1) == $0.getImport()!.variable + && wasmSignature == $0.getImport()!.signature }) { return Data([0x10]) + Leb128.unsignedEncode(index) } else { @@ -1946,19 +2016,21 @@ public class WasmLifter { let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) var inputIndex = 1 + op.parameterCount let catchTable: Data = try op.catches.map { - switch $0 { - case .Ref, .NoRef: - let tag = try resolveIdx(ofType: .tag, for: wasmInstruction.input(inputIndex)) - let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex + 1)) - 1 - let result = Data([$0.rawValue]) + Leb128.unsignedEncode(tag) + Leb128.unsignedEncode(depth) - inputIndex += 2 - return result - case .AllRef, .AllNoRef: - let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex)) - 1 - inputIndex += 1 - return Data([$0.rawValue]) + Leb128.unsignedEncode(depth) - } - }.reduce(Data(), +) + switch $0 { + case .Ref, .NoRef: + let tag = try resolveIdx(ofType: .tag, for: wasmInstruction.input(inputIndex)) + let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex + 1)) - 1 + let result = + Data([$0.rawValue]) + Leb128.unsignedEncode(tag) + + Leb128.unsignedEncode(depth) + inputIndex += 2 + return result + case .AllRef, .AllNoRef: + let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex)) - 1 + inputIndex += 1 + return Data([$0.rawValue]) + Leb128.unsignedEncode(depth) + } + }.reduce(Data(), +) return [0x1F] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!) + Leb128.unsignedEncode(op.catches.count) @@ -1972,12 +2044,15 @@ public class WasmLifter { case .wasmBeginCatchAll(_): return Data([0x19]) case .wasmBeginCatch(_): - return Data([0x07] + Leb128.unsignedEncode(try resolveIdx(ofType: .tag, for: wasmInstruction.input(1)))) + return Data( + [0x07] + + Leb128.unsignedEncode( + try resolveIdx(ofType: .tag, for: wasmInstruction.input(1)))) case .wasmEndLoop(_), - .wasmEndIf(_), - .wasmEndTryTable(_), - .wasmEndTry(_), - .wasmEndBlock(_): + .wasmEndIf(_), + .wasmEndTryTable(_), + .wasmEndTry(_), + .wasmEndBlock(_): // Basically the same as EndBlock, just an explicit instruction. return Data([0x0B]) case .wasmEndTryDelegate(_): @@ -1988,7 +2063,10 @@ public class WasmLifter { } return Data([0x18]) + Leb128.unsignedEncode(branchDepth) case .wasmThrow(_): - return Data([0x08] + Leb128.unsignedEncode(try resolveIdx(ofType: .tag, for: wasmInstruction.input(0)))) + return Data( + [0x08] + + Leb128.unsignedEncode( + try resolveIdx(ofType: .tag, for: wasmInstruction.input(0)))) case .wasmThrowRef(_): return Data([0x0A]) case .wasmRethrow(_): @@ -1996,16 +2074,19 @@ public class WasmLifter { return Data([0x09] + Leb128.unsignedEncode(blockDepth)) case .wasmBranch(let op): let branchDepth = try branchDepthFor(label: wasmInstruction.input(0)) - return Data([0x0C]) + Leb128.unsignedEncode(branchDepth) + Array(repeating: 0x1a, count: op.parameterCount) + return Data([0x0C]) + Leb128.unsignedEncode(branchDepth) + + Array(repeating: 0x1a, count: op.parameterCount) case .wasmBranchIf(let op): currentFunction!.addBranchHint(op.hint) let branchDepth = try branchDepthFor(label: wasmInstruction.input(0)) - return Data([0x0D]) + Leb128.unsignedEncode(branchDepth) + Array(repeating: 0x1a, count: op.parameterCount) + return Data([0x0D]) + Leb128.unsignedEncode(branchDepth) + + Array(repeating: 0x1a, count: op.parameterCount) case .wasmBranchTable(let op): let depths = try (0...op.valueCount).map { try branchDepthFor(label: wasmInstruction.input($0)) } - return Data([0x0E]) + Leb128.unsignedEncode(op.valueCount) + depths.map(Leb128.unsignedEncode).joined() + return Data([0x0E]) + Leb128.unsignedEncode(op.valueCount) + + depths.map(Leb128.unsignedEncode).joined() case .wasmBeginIf(let op): currentFunction!.addBranchHint(op.hint) let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) @@ -2029,7 +2110,10 @@ public class WasmLifter { storeInstruction = Data([0x21]) + Leb128.unsignedEncode(stackSlot) } else { // It has to be global then. Do what StoreGlobal does. - storeInstruction = Data([0x24]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: wasmInstruction.input(0))) + storeInstruction = + Data([0x24]) + + Leb128.unsignedEncode( + try resolveIdx(ofType: .global, for: wasmInstruction.input(0))) } // Load the input now. For "internal" variables, we should not have an expression. @@ -2039,7 +2123,10 @@ public class WasmLifter { out += Data([0x20]) + Leb128.unsignedEncode(stackSlot) } else { // Has to be a global then. Do what LoadGlobal does. - out += Data([0x23]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: wasmInstruction.input(1))) + out += + Data([0x23]) + + Leb128.unsignedEncode( + try resolveIdx(ofType: .global, for: wasmInstruction.input(1))) } return out + storeInstruction @@ -2052,58 +2139,78 @@ public class WasmLifter { case .constSimd128(let op): return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(12) + Data(op.value) case .wasmSimd128IntegerUnOp(let op): - assert(WasmSimd128IntegerUnOpKind.allCases.count == 17, "New WasmSimd128IntegerUnOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerUnOpKind.allCases.count == 17, + "New WasmSimd128IntegerUnOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .i8x16: 0x5C case .i16x8: 0x7C case .i32x4: 0x9C case .i64x2: 0xBC default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") - } - var encoding = Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.unOpKind.rawValue) + } + var encoding = + Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.unOpKind.rawValue) // For most of the instructions we have to add another 0x01 byte add the end of the encoding. switch op.shape { - case .i8x16: + case .i8x16: + break + case .i16x8, .i32x4, .i64x2: + switch op.unOpKind { + case .extadd_pairwise_i8x16_s, + .extadd_pairwise_i8x16_u: break - case .i16x8, .i32x4, .i64x2: switch op.unOpKind { - case .extadd_pairwise_i8x16_s, - .extadd_pairwise_i8x16_u: - break - default: - encoding += Leb128.unsignedEncode(0x01) + default: + encoding += Leb128.unsignedEncode(0x01) } - default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") + default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") } return encoding case .wasmSimd128IntegerBinOp(let op): - assert(WasmSimd128IntegerBinOpKind.allCases.count == 26, "New WasmSimd128IntegerBinOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerBinOpKind.allCases.count == 26, + "New WasmSimd128IntegerBinOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .i8x16: 0x5C case .i16x8: 0x7C case .i32x4: 0x9C case .i64x2: 0xBC default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerBinOp") - } - var encoding = Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.binOpKind.rawValue) + } + var encoding = + Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.binOpKind.rawValue) // Apart from .i8x16 shape, the encoding has another 0x01 byte at the end of the encoding. - if (op.shape != .i8x16) { + if op.shape != .i8x16 { encoding += Leb128.unsignedEncode(0x01) } return encoding case .wasmSimd128IntegerTernaryOp(let op): - assert(WasmSimd128IntegerTernaryOpKind.allCases.count == 2, "New WasmSimd128IntegerTernaryOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerTernaryOpKind.allCases.count == 2, + "New WasmSimd128IntegerTernaryOpKind added: check if the encoding is still correct!" + ) + let base = + switch op.shape { case .i8x16: 0x100 case .i16x8: 0x101 case .i32x4: 0x102 case .i64x2: 0x103 - default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerTernaryOp") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + Leb128.unsignedEncode(0x01) + default: + fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerTernaryOp") + } + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + + Leb128.unsignedEncode(0x01) case .wasmSimd128FloatUnOp(let op): - assert(WasmSimd128FloatUnOpKind.allCases.count == 7, "New WasmSimd128FloatUnOpKind added: check if the encoding is still correct!") - let encoding = switch op.shape { - case .f32x4: switch op.unOpKind { + assert( + WasmSimd128FloatUnOpKind.allCases.count == 7, + "New WasmSimd128FloatUnOpKind added: check if the encoding is still correct!") + let encoding = + switch op.shape { + case .f32x4: + switch op.unOpKind { case .ceil: Leb128.unsignedEncode(0x67) case .floor: Leb128.unsignedEncode(0x68) case .trunc: Leb128.unsignedEncode(0x69) @@ -2111,8 +2218,9 @@ public class WasmLifter { case .abs: Leb128.unsignedEncode(0xE0) + Leb128.unsignedEncode(0x01) case .neg: Leb128.unsignedEncode(0xE1) + Leb128.unsignedEncode(0x01) case .sqrt: Leb128.unsignedEncode(0xE3) + Leb128.unsignedEncode(0x01) - } - case .f64x2: switch op.unOpKind { + } + case .f64x2: + switch op.unOpKind { case .ceil: Leb128.unsignedEncode(0x74) case .floor: Leb128.unsignedEncode(0x75) case .trunc: Leb128.unsignedEncode(0x7A) @@ -2120,49 +2228,70 @@ public class WasmLifter { case .abs: Leb128.unsignedEncode(0xEC) + Leb128.unsignedEncode(0x01) case .neg: Leb128.unsignedEncode(0xED) + Leb128.unsignedEncode(0x01) case .sqrt: Leb128.unsignedEncode(0xEF) + Leb128.unsignedEncode(0x01) - } + } default: fatalError("Shape \(op.shape) not supported for WasmSimd128FloatUnOp") - } + } return Data([Prefix.Simd.rawValue]) + encoding case .wasmSimd128FloatBinOp(let op): - assert(WasmSimd128FloatBinOpKind.allCases.count == 10, "New WasmSimd128FloatBinOpKind added: check if the encoding is still correct!") - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(op.getOpcode()) + Leb128.unsignedEncode(0x01) + assert( + WasmSimd128FloatBinOpKind.allCases.count == 10, + "New WasmSimd128FloatBinOpKind added: check if the encoding is still correct!") + return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(op.getOpcode()) + + Leb128.unsignedEncode(0x01) case .wasmSimd128FloatTernaryOp(let op): - assert(WasmSimd128FloatTernaryOpKind.allCases.count == 2, "New WasmSimd128FloatTernaryOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128FloatTernaryOpKind.allCases.count == 2, + "New WasmSimd128FloatTernaryOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .f32x4: 0x100 case .f64x2: 0x102 default: fatalError("Shape \(op.shape) not supported for WasmSimd128FloatTernaryOp") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + Leb128.unsignedEncode(0x01) + } + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + + Leb128.unsignedEncode(0x01) case .wasmSimd128Compare(let op): - assert(WasmIntegerCompareOpKind.allCases.count == 10, "New WasmIntegerCompareOpKind added: check if the encoding is still correct!") - assert(WasmFloatCompareOpKind.allCases.count == 6, "New WasmFloatCompareOpKind added: check if the encoding is still correct!") + assert( + WasmIntegerCompareOpKind.allCases.count == 10, + "New WasmIntegerCompareOpKind added: check if the encoding is still correct!") + assert( + WasmFloatCompareOpKind.allCases.count == 6, + "New WasmFloatCompareOpKind added: check if the encoding is still correct!") switch op.shape { case .i8x16: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x23 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x23 + op.compareOpKind.toInt()) case .i16x8: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x2D + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x2D + op.compareOpKind.toInt()) case .i32x4: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x37 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x37 + op.compareOpKind.toInt()) case .i64x2: if case .iKind(let value) = op.compareOpKind { - let temp = switch value { + let temp = + switch value { case .Eq: 0 case .Ne: 1 case .Lt_s: 2 case .Gt_s: 3 case .Le_s: 4 case .Ge_s: 5 - default: fatalError("Shape \(op.shape) does not have \(op.compareOpKind) instruction") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0xD6 + temp) + Leb128.unsignedEncode(0x01) + default: + fatalError( + "Shape \(op.shape) does not have \(op.compareOpKind) instruction") + } + return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0xD6 + temp) + + Leb128.unsignedEncode(0x01) } fatalError("unreachable") case .f32x4: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x41 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x41 + op.compareOpKind.toInt()) case .f64x2: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x47 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x47 + op.compareOpKind.toInt()) } case .wasmSimdSplat(let op): return Data([Prefix.Simd.rawValue, op.kind.rawValue]) @@ -2178,10 +2307,11 @@ public class WasmLifter { let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + Leb128.unsignedEncode(op.lane) - case .wasmSimdLoad(let op): + case .wasmSimdLoad(let op): // The memory immediate is {staticOffset, align} where align is 0 by default. Use signed encoding for potential bad (i.e. negative) offsets. let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + + Leb128.signedEncode(Int(op.staticOffset)) case .wasmArrayNewFixed(let op): let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) let arrayIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) @@ -2193,7 +2323,8 @@ public class WasmLifter { case .wasmArrayLen(_): return Data([Prefix.GC.rawValue, 0x0F]) case .wasmArrayGet(let op): - let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmArrayTypeDescription + let typeDesc = + typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmArrayTypeDescription let opCode: UInt8 = typeDesc.elementType.isPacked() ? (op.isSigned ? 0x0C : 0x0D) : 0x0B let arrayIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) return Data([Prefix.GC.rawValue, opCode]) + arrayIndex @@ -2210,8 +2341,10 @@ public class WasmLifter { let structIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) return Data([Prefix.GC.rawValue, 0x01]) + structIndex case .wasmStructGet(let op): - let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmStructTypeDescription - let opCode: UInt8 = typeDesc.fields[op.fieldIndex].type.isPacked() ? (op.isSigned ? 0x03 : 0x04) : 0x02 + let typeDesc = + typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmStructTypeDescription + let opCode: UInt8 = + typeDesc.fields[op.fieldIndex].type.isPacked() ? (op.isSigned ? 0x03 : 0x04) : 0x02 let structIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) let fieldIndex = Leb128.unsignedEncode(op.fieldIndex) return Data([Prefix.GC.rawValue, opCode]) + structIndex + fieldIndex @@ -2251,7 +2384,7 @@ public class WasmLifter { return Data() default: - fatalError("unreachable") + fatalError("unreachable") } } } diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index ddc493bc7..39f27e327 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -27,11 +27,11 @@ struct BlockReducer: Reducer { reduceObjectLiteral(group.block(0), with: helper) case .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter: + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter: assert(group.numBlocks == 1) reduceFunctionInObjectLiteral(group.block(0), with: helper) @@ -39,22 +39,22 @@ struct BlockReducer: Reducer { reduceClassDefinition(group.block(0), with: helper) case .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassStaticInitializer, .beginClassPrivateMethod: + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, - .beginDoWhileLoopBody, - .beginForLoopInitializer, - .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct, - .beginRepeatLoop: + .beginDoWhileLoopBody, + .beginForLoopInitializer, + .beginForInLoop, + .beginForOfLoop, + .beginForOfLoopWithDestruct, + .beginRepeatLoop: reduceLoop(group, with: helper) case .beginIf: @@ -67,41 +67,41 @@ struct BlockReducer: Reducer { reduceBeginSwitch(group, with: helper) case .beginSwitchCase, - .beginSwitchDefaultCase: - // These instructions are handled in reduceBeginSwitch. - break + .beginSwitchDefaultCase: + // These instructions are handled in reduceBeginSwitch. + break case .beginWith: reduceGenericBlockGroup(group, with: helper) case .beginPlainFunction, - .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor: + .beginArrowFunction, + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor: reduceFunctionOrConstructor(group, with: helper) case .beginCodeString: reduceCodeString(group, with: helper) case .beginBlockStatement, - .beginWasmFunction, - .beginWasmModule, - .wasmBeginTryDelegate, - .wasmBeginTryTable: + .beginWasmFunction, + .beginWasmModule, + .wasmBeginTryDelegate, + .wasmBeginTryTable: reduceGenericBlockGroup(group, with: helper) case .wasmBeginBlock, - .wasmBeginLoop: + .wasmBeginLoop: let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper) if rewroteProgram { return } case .wasmBeginCatchAll, - .wasmBeginCatch: + .wasmBeginCatch: // These instructions are handled in the reduceWasmTryCatch. break case .wasmBeginTry: @@ -209,7 +209,8 @@ struct BlockReducer: Reducer { helper.tryReplacements(replacements, renumberVariables: true, expectCodeToBeValid: false) } - private func reduceFunctionInClassDefinition(_ function: Block, with helper: MinimizationHelper) { + private func reduceFunctionInClassDefinition(_ function: Block, with helper: MinimizationHelper) + { // Similar to the object literal case, the instructions inside the function body aren't valid inside // the surrounding class definition, so we can only try to temove the entire function. helper.tryNopping(function.allInstructions) @@ -224,7 +225,7 @@ struct BlockReducer: Reducer { for block in loop.blocks { for instr in helper.code.body(of: block) { if instr.isBlockEnd { - inNestedLoop = nestedBlocks.pop() + inNestedLoop = nestedBlocks.pop() } if instr.isBlockStart { let isLoop = instr.op.contextOpened.contains(.loop) @@ -256,7 +257,7 @@ struct BlockReducer: Reducer { if group.numBlocks == 2 { // First try to remove the else block. let elseBlock = group.block(1) - let rangeToNop = Array(elseBlock.head ..< elseBlock.tail) + let rangeToNop = Array(elseBlock.head.. Bool { + private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper) + -> Bool + { // Try to remove just the block. var candidates = group.blockInstructionIndices if helper.tryNopping(candidates) { @@ -337,12 +344,13 @@ struct BlockReducer: Reducer { let endInstrInputs = endInstr.inputs.dropFirst() var varReplacements = Dictionary( uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), blockInputs)) - varReplacements.merge(zip(endInstr.outputs, endInstrInputs.map {varReplacements[$0] ?? $0}), - uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) + varReplacements.merge( + zip(endInstr.outputs, endInstrInputs.map { varReplacements[$0] ?? $0 }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) var newCode = Code() for (i, instr) in helper.code.enumerated() { if i == group.head || i == group.tail { - continue // Skip the block begin and end. + continue // Skip the block begin and end. } let newInouts = instr.inouts.map({ varReplacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -375,7 +383,9 @@ struct BlockReducer: Reducer { // Start iterating over the switch case statements. var instructionIdx = group.head + 1 while instructionIdx < group.tail { - if helper.code[instructionIdx].op is BeginSwitchCase || helper.code[instructionIdx].op is BeginSwitchDefaultCase { + if helper.code[instructionIdx].op is BeginSwitchCase + || helper.code[instructionIdx].op is BeginSwitchDefaultCase + { let block = helper.code.block(startingAt: instructionIdx) blocks.append(block) candidates.append(block.head) @@ -423,7 +433,9 @@ struct BlockReducer: Reducer { // Start iterating over the try catch statements. var instructionIdx = group.head + 1 while instructionIdx < group.tail { - if helper.code[instructionIdx].op is WasmBeginCatch || helper.code[instructionIdx].op is WasmBeginCatchAll { + if helper.code[instructionIdx].op is WasmBeginCatch + || helper.code[instructionIdx].op is WasmBeginCatchAll + { let block = helper.code.block(startingAt: instructionIdx) blocks.append(block) candidates.append(block.head) @@ -446,14 +458,14 @@ struct BlockReducer: Reducer { // Skip the last instruction as it is both the .endBlock as well as the .startBlock for // the next catch (or the overall end of the try). let allInstructions = block.allInstructions - helper.tryNopping(Array(allInstructions[0.. Bool { let label = helper.code[group.head].innerOutputs.first! - return ((group.head + 1)..= elseBlock.head && i <= elseBlock.tail) { - continue // Skip the WasmBeginIf and the else block. + continue // Skip the WasmBeginIf and the else block. } - let newInouts = instr.inouts.map {varReplacements[$0] ?? $0} + let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) } newCode.renumberVariables() @@ -535,22 +556,26 @@ struct BlockReducer: Reducer { return true } } - do { // Try to replace the if-else with the else body. + do { // Try to replace the if-else with the else body. let beginElseInstr = helper.code[elseBlock.head] // "Shortcut" bypassing the WasmBeginElse by directly using the inputs into the // WasmBeginIf. var varReplacements = Dictionary( - uniqueKeysWithValues: zip(beginElseInstr.innerOutputs.dropFirst(), beginIfInstr.inputs.dropFirst())) + uniqueKeysWithValues: zip( + beginElseInstr.innerOutputs.dropFirst(), beginIfInstr.inputs.dropFirst())) // Replace all usages of the WasmEndIf outputs with the results of the else block // which are the inputs into the WasmEndIf block. varReplacements.merge( - zip(helper.code[elseBlock.tail].outputs, - helper.code[elseBlock.tail].inputs.dropFirst().map {varReplacements[$0] ?? $0}), - uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) + zip( + helper.code[elseBlock.tail].outputs, + helper.code[elseBlock.tail].inputs.dropFirst().map { + varReplacements[$0] ?? $0 + }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) var newCode = Code() for (i, instr) in helper.code.enumerated() { if i == elseBlock.tail || (i >= ifBlock.head && i <= ifBlock.tail) { - continue // Skip the WasmBeginIf and the if true block. + continue // Skip the WasmBeginIf and the if true block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -565,7 +590,9 @@ struct BlockReducer: Reducer { return false } - private func reduceFunctionOrConstructor(_ function: BlockGroup, with helper: MinimizationHelper) { + private func reduceFunctionOrConstructor( + _ function: BlockGroup, with helper: MinimizationHelper + ) { assert(helper.code[function.head].op is BeginAnySubroutine) assert(helper.code[function.tail].op is EndAnySubroutine) @@ -597,7 +624,11 @@ struct BlockReducer: Reducer { // This avoids the need to find the `eval` call that use the CodeString. // Indices stay valid throughout this reduction. var replacements = [(Int, Instruction)]() - replacements.append((codestring.head, Instruction(LoadString(value: ""), output: helper.code[codestring.head].output))) + replacements.append( + ( + codestring.head, + Instruction(LoadString(value: ""), output: helper.code[codestring.head].output) + )) replacements.append((codestring.tail, Instruction(Nop()))) if helper.tryReplacements(replacements) { // Success! diff --git a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift index 43820e996..c1a4357c4 100644 --- a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift @@ -41,7 +41,7 @@ struct DataFlowSimplifier: Reducer { } // For now, we only consider simple instructions as candidates. - guard instr.isSimple else { continue } + guard instr.isSimple else { continue } // The instruction must have at least one output and one input, // otherwise it wouldn't be an intermediate node. guard instr.numOutputs > 0 else { continue } @@ -54,7 +54,9 @@ struct DataFlowSimplifier: Reducer { } // Remove those candidates whose outputs aren't used. - candidates = candidates.filter({ helper.code[$0].allOutputs.map({ uses[$0]! }).reduce(0, +) > 0 }) + candidates = candidates.filter({ + helper.code[$0].allOutputs.map({ uses[$0]! }).reduce(0, +) > 0 + }) // Filter out Wasm instructions where the types would be invalid if we replaced them. candidates = candidates.filter({ @@ -69,7 +71,9 @@ struct DataFlowSimplifier: Reducer { if operation is WasmOperation { guard operation.numOutputs == 1 else { return false } let outputType = typer.type(of: helper.code[$0].output) - let filteredOutputs = helper.code[$0].inputs.map(typer.type).filter {$0.Is(outputType)} + let filteredOutputs = helper.code[$0].inputs.map(typer.type).filter { + $0.Is(outputType) + } // If we have outputs, we can actually try to replace this. return !filteredOutputs.isEmpty } else { @@ -90,10 +94,13 @@ struct DataFlowSimplifier: Reducer { // if the candidate is a Wasm operation we need to preserve types. if instr.op is WasmOperation { let outputType = typer.type(of: instr.output) - let filteredOutputs = instr.inputs.map(typer.type).enumerated().filter {$0.element.Is(outputType)} + let filteredOutputs = instr.inputs.map(typer.type).enumerated().filter { + $0.element.Is(outputType) + } if !filteredOutputs.isEmpty { // Now pick a random index and choose that input as a replacement. - replacement = instr.inputs[chooseUniform(from: filteredOutputs.map { $0.offset })] + replacement = + instr.inputs[chooseUniform(from: filteredOutputs.map { $0.offset })] } } else { // Pick a random input as replacement. Here we could attempt to be smarter and @@ -125,4 +132,3 @@ struct DataFlowSimplifier: Reducer { } } } - diff --git a/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift b/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift index 2e5746a39..c6ea5a438 100644 --- a/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift +++ b/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift @@ -36,7 +36,8 @@ struct DeduplicatingReducer: Reducer { let oldInouts = Array(instr.inouts) let newInouts = oldInouts.map({ deduplicatedVariables[$0] ?? $0 }) if oldInouts != newInouts { - replacements.append((instr.index, Instruction(instr.op, inouts: newInouts, flags: instr.flags))) + replacements.append( + (instr.index, Instruction(instr.op, inouts: newInouts, flags: instr.flags))) } // Scope management. @@ -57,7 +58,10 @@ struct DeduplicatingReducer: Reducer { deduplicatedVariables[instr.output] = replacement } else { // Each builtin must only be present once (all other instances are replaced with the first one). - assert(visibleBuiltins.elementsStartingAtBottom().allSatisfy({ !$0.contains(op.variableName) })) + assert( + visibleBuiltins.elementsStartingAtBottom().allSatisfy({ + !$0.contains(op.variableName) + })) visibleBuiltins.top.append(op.variableName) variableForName[op.variableName] = instr.output } diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index dcb039c1f..731478c45 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -44,54 +44,54 @@ struct InliningReducer: Reducer { for instr in code { // Identify candidates. switch instr.op.opcode { - // Currently we only inline plain functions as that guarantees that the resulting code is always valid. - // Otherwise, we might for example attempt to inline an async function containing an 'await', which would not be valid. - // This works fine because the ReplaceReducer will attempt to turn "special" functions into plain functions. + // Currently we only inline plain functions as that guarantees that the resulting code is always valid. + // Otherwise, we might for example attempt to inline an async function containing an 'await', which would not be valid. + // This works fine because the ReplaceReducer will attempt to turn "special" functions into plain functions. case .beginPlainFunction: candidates[instr.output] = (callCount: 0, index: instr.index) fallthrough case .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor, - .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter, - .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassStaticInitializer, .beginClassPrivateMethod: + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor, + .beginObjectLiteralMethod, + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, + .beginClassConstructor, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endConstructor, - .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter, - .endClassConstructor, - .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter, - .endClassStaticInitializer, .endClassPrivateMethod: + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endConstructor, + .endObjectLiteralMethod, + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, + .endClassConstructor, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter, + .endClassStaticInitializer, .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) @@ -115,14 +115,14 @@ struct InliningReducer: Reducer { // Can't inline functions that are passed as arguments to other functions. deleteCandidates(instr.inputs.dropFirst()) case .loadDisposableVariable, - .createNamedDisposableVariable, - .loadAsyncDisposableVariable, - .createNamedAsyncDisposableVariable: + .createNamedDisposableVariable, + .loadAsyncDisposableVariable, + .createNamedAsyncDisposableVariable: // Can't inline functions that are also used as a disposable variable. deleteCandidates(instr.inputs) fallthrough case .loadNewTarget, - .loadArguments: + .loadArguments: // Can't inline functions if they access their arguments or new.target. // Or if they create a disposable variable. if let function = activeSubroutineDefinitions.last! { @@ -136,7 +136,7 @@ struct InliningReducer: Reducer { } } - return candidates.values.filter({ $0.callCount == 1}).map({ $0.index }) + return candidates.values.filter({ $0.callCount == 1 }).map({ $0.index }) } /// Returns a new Code object with the specified function inlined into its callsite. diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 858b39003..da9d32ad3 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -30,11 +30,14 @@ struct InstructionSimplifier: Reducer { if begin is BeginPlainFunction { continue } let functionName = (begin as? BeginAnyNamedFunction)?.functionName ?? nil - let newBegin = Instruction(BeginPlainFunction(parameters: begin.parameters, functionName: functionName), inouts: helper.code[group.head].inouts, flags: .empty) + let newBegin = Instruction( + BeginPlainFunction(parameters: begin.parameters, functionName: functionName), + inouts: helper.code[group.head].inouts, flags: .empty) let newEnd = Instruction(EndPlainFunction()) // The resulting code may be invalid as we may be changing the context inside the body (e.g. turning an async function into a plain one). - helper.tryReplacements([(group.head, newBegin), (group.tail, newEnd)], expectCodeToBeValid: false) + helper.tryReplacements( + [(group.head, newBegin), (group.tail, newEnd)], expectCodeToBeValid: false) } } @@ -56,7 +59,9 @@ struct InstructionSimplifier: Reducer { } if let op = newOp { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(op, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(op, inouts: instr.inouts, flags: .empty)) } } } @@ -78,7 +83,9 @@ struct InstructionSimplifier: Reducer { case .constructWithSpread(let op): newOp = Construct(numArguments: op.numArguments, isGuarded: op.isGuarded) case .callMethodWithSpread(let op): - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments, + isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): newOp = CallComputedMethod(numArguments: op.numArguments, isGuarded: op.isGuarded) @@ -91,7 +98,9 @@ struct InstructionSimplifier: Reducer { } if let op = newOp { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(op, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(op, inouts: instr.inouts, flags: .empty)) } } } @@ -103,7 +112,9 @@ struct InstructionSimplifier: Reducer { guard let op = instr.op as? GuardableOperation else { continue } let newOp = GuardableOperation.disableGuard(of: op) if newOp !== op { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) } } } @@ -129,10 +140,16 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, propertyName) in op.properties.enumerated() { - newCode.append(Instruction(GetProperty(propertyName: propertyName, isGuarded: false), output: outputs[i], inputs: [instr.input(0)])) + newCode.append( + Instruction( + GetProperty(propertyName: propertyName, isGuarded: false), + output: outputs[i], inputs: [instr.input(0)])) } if op.hasRestElement { - newCode.append(Instruction(DestructObject(properties: [], hasRestElement: true), output: outputs.last!, inputs: [instr.input(0)])) + newCode.append( + Instruction( + DestructObject(properties: [], hasRestElement: true), + output: outputs.last!, inputs: [instr.input(0)])) } keepInstruction = false case .destructArray(let op): @@ -144,9 +161,15 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, idx) in op.indices.enumerated() { if i == op.indices.count - 1 && op.lastIsRest { - newCode.append(Instruction(DestructArray(indices: [idx], lastIsRest: true), output: outputs.last!, inputs: [instr.input(0)])) + newCode.append( + Instruction( + DestructArray(indices: [idx], lastIsRest: true), + output: outputs.last!, inputs: [instr.input(0)])) } else { - newCode.append(Instruction(GetElement(index: idx, isGuarded: false), output: outputs[i], inputs: [instr.input(0)])) + newCode.append( + Instruction( + GetElement(index: idx, isGuarded: false), output: outputs[i], + inputs: [instr.input(0)])) } } keepInstruction = false diff --git a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index 11169adb2..edf76df0c 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -41,12 +41,15 @@ struct LoopSimplifier: Reducer { case .beginRepeatLoop: tryReduceRepeatLoopIterationCount(group, with: helper) case .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct: + .beginForOfLoop, + .beginForOfLoopWithDestruct: // These loops are (usually) guaranteed to terminate, and should probably anyway not be replaced by repeat-loops. break default: - assert(group.blocks.allSatisfy({ !helper.code[$0.head].op.contextOpened.contains(.loop) })) + assert( + group.blocks.allSatisfy({ + !helper.code[$0.head].op.contextOpened.contains(.loop) + })) } } @@ -54,7 +57,9 @@ struct LoopSimplifier: Reducer { findAndMergeNestedRepeatLoops(with: helper) } - private func tryReplaceForLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceForLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginForLoopInitializer @@ -93,10 +98,14 @@ struct LoopSimplifier: Reducer { let headerIndex = newCode.count let needLoopVariable = beginConditionBlock.numInnerOutputs > 0 let loopVar = needLoopVariable ? beginConditionBlock.innerOutput(0) : nil - newCode.append(Instruction(BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) + newCode.append( + Instruction( + BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), + inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) // Append condition, body, and afterthought code - var replacements = Dictionary(uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) + var replacements = [Variable: Variable]( + uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: conditionBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -104,7 +113,8 @@ struct LoopSimplifier: Reducer { let bodyBlock = group.block(3) assert(helper.code[bodyBlock.head].op is BeginForLoopBody) - replacements = Dictionary(uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) + replacements = [Variable: Variable]( + uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: bodyBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -112,7 +122,10 @@ struct LoopSimplifier: Reducer { let afterthoughtBlock = group.block(2) assert(helper.code[afterthoughtBlock.head].op is BeginForLoopAfterthought) - replacements = Dictionary(uniqueKeysWithValues: helper.code[afterthoughtBlock.head].innerOutputs.map({ ($0, loopVar!) })) + replacements = [Variable: Variable]( + uniqueKeysWithValues: helper.code[afterthoughtBlock.head].innerOutputs.map({ + ($0, loopVar!) + })) for instr in helper.code.body(of: afterthoughtBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -121,10 +134,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: headerIndex, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: headerIndex, + using: helper) } - private func tryReplaceWhileLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceWhileLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginWhileLoopHeader @@ -161,10 +178,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, + using: helper) } - private func tryReplaceDoWhileLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceDoWhileLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginDoWhileLoopBody @@ -201,10 +222,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, + using: helper) } - private func tryReduceRepeatLoopIterationCount(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReduceRepeatLoopIterationCount( + _ group: BlockGroup, with helper: MinimizationHelper + ) { let originalLoopHeader = helper.code[group.head].op as! BeginRepeatLoop guard originalLoopHeader.iterations > commonLoopIterationCounts[0] else { // Loop already has the minimum number of iterations. @@ -217,27 +242,41 @@ struct LoopSimplifier: Reducer { } let replacement: Instruction if originalLoopHeader.exposesLoopCounter { - replacement = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), inouts: helper.code[group.head].inouts, flags: .empty) + replacement = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), + inouts: helper.code[group.head].inouts, flags: .empty) } else { - replacement = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) + replacement = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) } - if helper.tryReplacing(instructionAt: group.head, with: replacement, numExecutions: numTestExecutions) { + if helper.tryReplacing( + instructionAt: group.head, with: replacement, numExecutions: numTestExecutions) + { return } } } - private func tryReplacingWithShortestPossibleRepeatLoop(range: ClosedRange, with newCode: [Instruction], loopHeaderIndexInNewCode headerIndex: Int, using helper: MinimizationHelper) { + private func tryReplacingWithShortestPossibleRepeatLoop( + range: ClosedRange, with newCode: [Instruction], + loopHeaderIndexInNewCode headerIndex: Int, using helper: MinimizationHelper + ) { var newCode = newCode assert(newCode[headerIndex].op is BeginRepeatLoop) for numIterations in commonLoopIterationCounts { if newCode[headerIndex].numInnerOutputs > 0 { - newCode[headerIndex] = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), inouts: newCode[headerIndex].inouts, flags: .empty) + newCode[headerIndex] = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), + inouts: newCode[headerIndex].inouts, flags: .empty) } else { - newCode[headerIndex] = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) + newCode[headerIndex] = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) } // After this change, the variable numbers may no longer be sequential as we may have removed instructions with inner outputs. So we need to also renumber the variables. - if helper.tryReplacing(range: range, with: newCode, renumberVariables: true, numExecutions: numTestExecutions) { + if helper.tryReplacing( + range: range, with: newCode, renumberVariables: true, + numExecutions: numTestExecutions) + { return } } @@ -268,7 +307,8 @@ struct LoopSimplifier: Reducer { // // Would. var loops = [Block]() - for group in helper.code.findAllBlockGroups() where helper.code[group.head].op is BeginRepeatLoop { + for group in helper.code.findAllBlockGroups() + where helper.code[group.head].op is BeginRepeatLoop { assert(group.numBlocks == 1) loops.append(group.block(0)) } @@ -276,9 +316,11 @@ struct LoopSimplifier: Reducer { var nestedLoops = [(outerHead: Int, innerHead: Int, innerTail: Int, outerTail: Int)]() for (i, outerLoop) in loops.dropLast().enumerated() { let innerLoop = loops[i + 1] - let instructionsBeforeInnerLoop = helper.code[helper.code.index(after: outerLoop.head).. Bool { + func testAndCommit( + _ newCode: Code, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions, allowRemoving: Instruction.Flags = .empty + ) -> Bool { assert(!self.finalized) assert(numExecutions > 0) assert(!expectCodeToBeValid || newCode.isStaticallyValid()) @@ -144,7 +150,9 @@ class MinimizationHelper { var stillHasAspects = false performOnFuzzerQueue { for _ in 0.. Bool { + func tryReplacing( + instructionAt index: Int, with newInstr: Instruction, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var newCode = self.code assert(newCode[index].allOutputs == newInstr.allOutputs) newCode[index] = newInstr - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } @discardableResult - func tryInserting(_ newInstr: Instruction, at index: Int, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions) -> Bool { + func tryInserting( + _ newInstr: Instruction, at index: Int, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions + ) -> Bool { // Right now we don't expect to see any flags here on the new instruction. assert(newInstr.flags.isEmpty) @@ -187,18 +203,28 @@ class MinimizationHelper { newCode.append(instr) } - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions) } /// Remove the instruction at the given index if it does not negatively influence the programs previous behaviour. @discardableResult - func tryNopping(instructionAt index: Int, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { - return tryReplacing(instructionAt: index, with: nop(for: code[index]), expectCodeToBeValid: false, numExecutions: numExecutions, allowRemoving: flags) + func tryNopping( + instructionAt index: Int, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { + return tryReplacing( + instructionAt: index, with: nop(for: code[index]), expectCodeToBeValid: false, + numExecutions: numExecutions, allowRemoving: flags) } /// Attempt multiple replacements at once. @discardableResult - func tryReplacements(_ replacements: [(Int, Instruction)], renumberVariables: Bool = false, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryReplacements( + _ replacements: [(Int, Instruction)], renumberVariables: Bool = false, + expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var newCode = self.code for (index, newInstr) in replacements { @@ -210,11 +236,17 @@ class MinimizationHelper { } assert(newCode.variablesAreNumberedContinuously()) - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } @discardableResult - func tryReplacing(range: ClosedRange, with newCode: [Instruction], renumberVariables: Bool = false, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryReplacing( + range: ClosedRange, with newCode: [Instruction], renumberVariables: Bool = false, + expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { assert(range.count >= newCode.count) var replacements = [(Int, Instruction)]() @@ -230,12 +262,18 @@ class MinimizationHelper { replacements.append((indexOfInstructionToReplace, replacement)) } - return tryReplacements(replacements, renumberVariables: renumberVariables, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return tryReplacements( + replacements, renumberVariables: renumberVariables, + expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } /// Attempt the removal of multiple instructions at once. @discardableResult - func tryNopping(_ indices: [Int], expectCodeToBeValid: Bool = false, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryNopping( + _ indices: [Int], expectCodeToBeValid: Bool = false, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var replacements = [(Int, Instruction)]() for index in indices { replacements.append((index, nop(for: code[index]))) @@ -246,7 +284,9 @@ class MinimizationHelper { /// Create a Nop instruction for replacing the given instruction with. func nop(for instr: Instruction) -> Instruction { // We must preserve outputs here to keep variable number contiguous. - return Instruction(Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, flags: .empty) + return Instruction( + Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, + flags: .empty) } } diff --git a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift index 6254e0971..45180278c 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift @@ -38,39 +38,58 @@ struct MinimizationPostProcessor { var replacementInstruction: Instruction? = nil switch instr.op.opcode { case .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endObjectLiteralMethod, - .endObjectLiteralGetter: + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endObjectLiteralMethod, + .endObjectLiteralGetter: // Insert return statements at the end of functions, but only if there is not one already. if lastInstr.op is Return || !b.hasVisibleJsVariables { break } - addedInstruction = Instruction(Return(hasReturnValue: true), inputs: [b.randomJsVariable()]) + addedInstruction = Instruction( + Return(hasReturnValue: true), inputs: [b.randomJsVariable()]) case .callFunction(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } let args = b.randomArguments(forCalling: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(CallFunction(numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + CallFunction(numArguments: args.count, isGuarded: op.isGuarded), + output: instr.output, inputs: [instr.input(0)] + args) case .callMethod(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } - let args = b.randomArguments(forCallingMethod: op.methodName, on: instr.input(0)) + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } + let args = b.randomArguments( + forCallingMethod: op.methodName, on: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(CallMethod(methodName: op.methodName, numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + CallMethod( + methodName: op.methodName, numArguments: args.count, + isGuarded: op.isGuarded), output: instr.output, + inputs: [instr.input(0)] + args) case .construct(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } let args = b.randomArguments(forCalling: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(Construct(numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + Construct(numArguments: args.count, isGuarded: op.isGuarded), + output: instr.output, inputs: [instr.input(0)] + args) case .createArray: // Add initial values, but only if there are none currently. if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables { break } - let initialValues = Array(repeating: b.randomJsVariable(), count: Int.random(in: 1...5)) - replacementInstruction = Instruction(CreateArray(numInitialValues: initialValues.count), output: instr.output, inputs: initialValues) + let initialValues = [Variable]( + repeating: b.randomJsVariable(), count: Int.random(in: 1...5)) + replacementInstruction = Instruction( + CreateArray(numInitialValues: initialValues.count), output: instr.output, + inputs: initialValues) default: assert(!(instr.op is EndAnyFunction)) break @@ -98,8 +117,11 @@ struct MinimizationPostProcessor { // Step 2: Try to apply each change from step 1 on its own and verify that the change doesn't alter the program's behaviour. for change in changes { // Either we're adding a new instruction (in which case we're replacing a nop inserted in step 1), or changing the number of inputs of an existing instruction. - assert((helper.code[change.index].op is Nop && !(change.newInstruction.op is Nop)) || - (helper.code[change.index].op.name == change.newInstruction.op.name && helper.code[change.index].numInputs < change.newInstruction.numInputs)) + assert( + (helper.code[change.index].op is Nop && !(change.newInstruction.op is Nop)) + || (helper.code[change.index].op.name == change.newInstruction.op.name + && helper.code[change.index].numInputs < change.newInstruction.numInputs) + ) helper.tryReplacing(instructionAt: change.index, with: change.newInstruction) } diff --git a/Sources/Fuzzilli/Minimization/Minimizer.swift b/Sources/Fuzzilli/Minimization/Minimizer.swift index 2b59ce1b5..6bdf91ce4 100644 --- a/Sources/Fuzzilli/Minimization/Minimizer.swift +++ b/Sources/Fuzzilli/Minimization/Minimizer.swift @@ -42,16 +42,23 @@ public class Minimizer: ComponentBase { /// /// Minimization will not modify the given program. Instead, it produce a new Program instance. /// Once minimization is finished, the passed block will be invoked on the fuzzer's queue with the minimized program. - func withMinimizedCopy(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double = 0.0, block: @escaping (Program) -> ()) { + func withMinimizedCopy( + _ program: Program, withAspects aspects: ProgramAspects, + limit minimizationLimit: Double = 0.0, block: @escaping (Program) -> Void + ) { minimizationQueue.async { - let minimizedCode = self.internalMinimize(program, withAspects: aspects, limit: minimizationLimit, performPostprocessing: true, runningSynchronously: false) + let minimizedCode = self.internalMinimize( + program, withAspects: aspects, limit: minimizationLimit, + performPostprocessing: true, runningSynchronously: false) self.fuzzer.async { let minimizedProgram: Program if self.fuzzer.config.enableInspection { - minimizedProgram = Program(code: minimizedCode, parent: program, contributors: program.contributors) + minimizedProgram = Program( + code: minimizedCode, parent: program, contributors: program.contributors) minimizedProgram.comments.add("Minimizing \(program.id)", at: .header) } else { - minimizedProgram = Program(code: minimizedCode, contributors: program.contributors) + minimizedProgram = Program( + code: minimizedCode, contributors: program.contributors) } block(minimizedProgram) } @@ -59,15 +66,25 @@ public class Minimizer: ComponentBase { } /// Synchronous version of withMinimizedCopy. Should only be used for tests since it otherwise blocks the fuzzer queue. - func minimize(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double = 0.0, performPostprocessing: Bool = true) -> Program { - let minimizedCode = internalMinimize(program, withAspects: aspects, limit: minimizationLimit, performPostprocessing: performPostprocessing, runningSynchronously: true) + func minimize( + _ program: Program, withAspects aspects: ProgramAspects, + limit minimizationLimit: Double = 0.0, performPostprocessing: Bool = true + ) -> Program { + let minimizedCode = internalMinimize( + program, withAspects: aspects, limit: minimizationLimit, + performPostprocessing: performPostprocessing, runningSynchronously: true) return Program(code: minimizedCode, parent: program, contributors: program.contributors) } - private func internalMinimize(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double, performPostprocessing: Bool, runningSynchronously: Bool) -> Code { + private func internalMinimize( + _ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double, + performPostprocessing: Bool, runningSynchronously: Bool + ) -> Code { assert(program.code.countIntructionsWith(flags: .notRemovable) == 0) - let helper = MinimizationHelper(for: aspects, forCode: program.code, of: fuzzer, runningOnFuzzerQueue: runningSynchronously) + let helper = MinimizationHelper( + for: aspects, forCode: program.code, of: fuzzer, + runningOnFuzzerQueue: runningSynchronously) helper.applyMinimizationLimit(limit: minimizationLimit) @@ -91,20 +108,24 @@ public class Minimizer: ComponentBase { DataFlowSimplifier(), VariadicInputReducer(), DeduplicatingReducer(), - WasmTypeGroupReducer() + WasmTypeGroupReducer(), ] for reducer in reducers { reducer.reduce(with: helper) // The reducers should not remove any instructions that we want to keep unconditionally. // The code might have more non-removable instructions due to other analyzers marking them as non-removable // but it should be at least more than we have seen at the start. - assert(helper.code.countIntructionsWith(flags: .notRemovable) >= helper.numKeptInstructions) + assert( + helper.code.countIntructionsWith(flags: .notRemovable) + >= helper.numKeptInstructions) assert(helper.code.isStaticallyValid()) } iterations += 1 guard iterations < 100 else { // This can happen if a reducer performs a no-op change in every iteration, e.g. replacing one instruction with the same instruction. This is considered a bug since it leads to this kind of issue. - logger.error("Fixpoint iteration for program minimization did not converge after 100 iterations for program:\n\(FuzzILLifter().lift(helper.code)). Aborting minimization.") + logger.error( + "Fixpoint iteration for program minimization did not converge after 100 iterations for program:\n\(FuzzILLifter().lift(helper.code)). Aborting minimization." + ) break } } while helper.didReduce diff --git a/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift b/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift index f641216ea..8b33138ab 100644 --- a/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift +++ b/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift @@ -37,7 +37,9 @@ struct VariadicInputReducer: Reducer { if op.numArguments == 1 { newOp = CallFunction(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallFunctionWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallFunctionWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .construct(let op): newOp = Construct(numArguments: op.numArguments - 1, isGuarded: op.isGuarded) @@ -45,30 +47,42 @@ struct VariadicInputReducer: Reducer { if op.numArguments == 1 { newOp = Construct(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = ConstructWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = ConstructWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .callMethod(let op): - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments - 1, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments - 1, + isGuarded: op.isGuarded) case .callMethodWithSpread(let op): if op.numArguments == 1 { - newOp = CallMethod(methodName: op.methodName, numArguments: 0, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments - 1, + spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) } case .callComputedMethod(let op): - newOp = CallComputedMethod(numArguments: op.numArguments - 1, isGuarded: op.isGuarded) + newOp = CallComputedMethod( + numArguments: op.numArguments - 1, isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): if op.numArguments == 1 { newOp = CallComputedMethod(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallComputedMethodWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallComputedMethodWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .callSuperConstructor(let op): newOp = CallSuperConstructor(numArguments: op.numArguments - 1) case .callPrivateMethod(let op): - newOp = CallPrivateMethod(methodName: op.methodName, numArguments: op.numArguments - 1) + newOp = CallPrivateMethod( + methodName: op.methodName, numArguments: op.numArguments - 1) case .callSuperMethod(let op): - newOp = CallSuperMethod(methodName: op.methodName, numArguments: op.numArguments - 1) + newOp = CallSuperMethod( + methodName: op.methodName, numArguments: op.numArguments - 1) case .bindFunction(let op): newOp = BindFunction(numInputs: op.numInputs - 1) case .createTemplateString(let op): diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index df6c149db..76b991b43 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -22,7 +22,6 @@ struct WasmTypeGroupReducer: Reducer { uses[input]? += 1 } - guard instr.op is WasmTypeOperation else { continue } // Define the usages for all WasmTypeOperation so that we also count usages of a type // inside a type group (i.e. by other type operations). @@ -31,7 +30,7 @@ struct WasmTypeGroupReducer: Reducer { } // For now, we only consider EndTypeGroup instructions. - guard case .wasmEndTypeGroup = instr.op.opcode else { continue } + guard case .wasmEndTypeGroup = instr.op.opcode else { continue } candidates.append(instr.index) for (input, output) in zip(instr.inputs, instr.outputs) { @@ -44,7 +43,9 @@ struct WasmTypeGroupReducer: Reducer { } // Remove those candidates whose outputs are all used. - candidates = candidates.filter {helper.code[$0].allOutputs.map({ uses[$0]! }).contains {$0 == 0}} + candidates = candidates.filter { + helper.code[$0].allOutputs.map({ uses[$0]! }).contains { $0 == 0 } + } if candidates.isEmpty { return @@ -56,9 +57,10 @@ struct WasmTypeGroupReducer: Reducer { let instr = helper.code[candidate] assert(instr.op is WasmEndTypeGroup) assert(instr.inputs.count == instr.outputs.count) - let newInoutsMap = zip(instr.inputs, instr.outputs).filter {uses[$0.1]! > 0} - let newInouts = newInoutsMap.map {$0.0} + newInoutsMap.map {$0.1} - let newInstr = Instruction(WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) + let newInoutsMap = zip(instr.inputs, instr.outputs).filter { uses[$0.1]! > 0 } + let newInouts = newInoutsMap.map { $0.0 } + newInoutsMap.map { $0.1 } + let newInstr = Instruction( + WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) replacements.append((candidate, newInstr)) } helper.tryReplacements(replacements, renumberVariables: true) diff --git a/Sources/Fuzzilli/Modules/NetworkSync.swift b/Sources/Fuzzilli/Modules/NetworkSync.swift index 807a11e21..49045cb04 100644 --- a/Sources/Fuzzilli/Modules/NetworkSync.swift +++ b/Sources/Fuzzilli/Modules/NetworkSync.swift @@ -14,6 +14,7 @@ import Foundation import libsocket + // Explicitly import `Foundation.UUID` to avoid the conflict with `WinSDK.UUID` import struct Foundation.UUID @@ -34,11 +35,11 @@ import struct Foundation.UUID // | 4 byte little endian | 4 byte little endian | length - 8 bytes | | // +----------------------+----------------------+------------------+-----------+ -fileprivate let messageHeaderSize = 8 -fileprivate let maxMessageSize = 1024 * 1024 * 1024 +private let messageHeaderSize = 8 +private let maxMessageSize = 1024 * 1024 * 1024 /// Protocol for an object capable of receiving messages. -fileprivate protocol MessageHandler { +private protocol MessageHandler { func handleMessage(_ payload: Data, ofType type: MessageType, from connection: Connection) func handleError(_ err: String, on connection: Connection) // The fuzzer instance on which to schedule the handler calls @@ -46,7 +47,7 @@ fileprivate protocol MessageHandler { } /// A connection to a network peer that speaks the above protocol. -fileprivate class Connection { +private class Connection { /// The file descriptor on POSIX or SOCKET handle on Windows of the socket. let socket: libsocket.libsocket_t @@ -73,7 +74,7 @@ fileprivate class Connection { private var currentMessageData = Data() /// Buffer to receive incoming data into. Must only be accessed on this connection's dispatch queue. - private var receiveBuffer = UnsafeMutableBufferPointer.allocate(capacity: 1024*1024) + private var receiveBuffer = UnsafeMutableBufferPointer.allocate(capacity: 1024 * 1024) /// Pending outgoing data. Must only be accessed on this connection's dispatch queue. private var sendQueue: [Data] = [] @@ -86,11 +87,13 @@ fileprivate class Connection { guard performHandshake() else { return nil } -#if os(Windows) - self.readSource = DispatchSource.makeReadSource(handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) -#else - self.readSource = DispatchSource.makeReadSource(fileDescriptor: socket, queue: self.queue) -#endif + #if os(Windows) + self.readSource = DispatchSource.makeReadSource( + handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) + #else + self.readSource = DispatchSource.makeReadSource( + fileDescriptor: socket, queue: self.queue) + #endif self.readSource?.setEventHandler { [weak self] in self?.handleDataAvailable() } @@ -119,7 +122,8 @@ fileprivate class Connection { // Send our id. let message = localId.uuidData let rv = message.withUnsafeBytes { data in - return libsocket.socket_send(socket, data.bindMemory(to: UInt8.self).baseAddress, message.count) + return libsocket.socket_send( + socket, data.bindMemory(to: UInt8.self).baseAddress, message.count) } guard rv == message.count else { return false } @@ -202,7 +206,8 @@ fileprivate class Connection { let startIndex = chunk.startIndex let rv = chunk.withUnsafeBytes { content -> Int in - return libsocket.socket_send(socket, content.bindMemory(to: UInt8.self).baseAddress, length) + return libsocket.socket_send( + socket, content.bindMemory(to: UInt8.self).baseAddress, length) } if rv < 0 { @@ -227,11 +232,13 @@ fileprivate class Connection { writeSource = nil } else if writeSource == nil { // Otherwise ensure we have an active write source to notify us when the next chunk can be sent -#if os(Windows) - writeSource = DispatchSource.makeWriteSource(handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) -#else - writeSource = DispatchSource.makeWriteSource(fileDescriptor: socket, queue: self.queue) -#endif + #if os(Windows) + writeSource = DispatchSource.makeWriteSource( + handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) + #else + writeSource = DispatchSource.makeWriteSource( + fileDescriptor: socket, queue: self.queue) + #endif writeSource?.setEventHandler { [weak self] in self?.sendPendingData() } @@ -279,7 +286,8 @@ fileprivate class Connection { let message = Data(currentMessageData.prefix(length)) // Explicitely make a copy of the data here so the discarded data is also freed from memory - currentMessageData = currentMessageData.subdata(in: totalMessageLength..= 1.0 else { - return // This can happen due to delays in queue processing + return // This can happen due to delays in queue processing } let execsPerSecond = self.currentExecs / interval @@ -217,17 +217,25 @@ public class Statistics: Module { fuzzer.timers.scheduleTask(every: 15 * Minutes) { self.logger.info("Mutator Statistics:") let nameMaxLength = fuzzer.mutators.map({ $0.name.count }).max()! - let maxSamplesGeneratedStringLength = fuzzer.mutators.map({ String($0.totalSamples).count }).max()! + let maxSamplesGeneratedStringLength = fuzzer.mutators.map({ + String($0.totalSamples).count + }).max()! for mutator in fuzzer.mutators { let name = mutator.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Self.percentageOrNa(mutator.correctnessRate, 7) let failureRate = Self.percentageOrNa(mutator.failureRate, 7) let timeoutRate = Self.percentageOrNa(mutator.timeoutRate, 6) - let interestingSamplesRate = Self.percentageOrNa(mutator.interestingSamplesRate, 7) - let avgInstructionsAdded = String(format: "%.2f", mutator.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) - let samplesGenerated = String(mutator.totalSamples).leftPadded(toLength: maxSamplesGeneratedStringLength) + let interestingSamplesRate = Self.percentageOrNa( + mutator.interestingSamplesRate, 7) + let avgInstructionsAdded = String( + format: "%.2f", mutator.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) + let samplesGenerated = String(mutator.totalSamples).leftPadded( + toLength: maxSamplesGeneratedStringLength) let crashesFound = mutator.crashesFound - self.logger.info(" \(name) : Correctness rate: \(correctnessRate), Failure rate: \(failureRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated), Total # of crashes found: \(crashesFound)") + self.logger.info( + " \(name) : Correctness rate: \(correctnessRate), Failure rate: \(failureRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated), Total # of crashes found: \(crashesFound)" + ) } } @@ -241,12 +249,18 @@ public class Statistics: Module { for stub in generator.parts { let name = stub.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Self.percentageOrNa(stub.correctnessRate, 7) - let interestingSamplesRate = Self.percentageOrNa(stub.interestingSamplesRate, 7) + let interestingSamplesRate = Self.percentageOrNa( + stub.interestingSamplesRate, 7) let timeoutRate = Self.percentageOrNa(stub.timeoutRate, 6) - let avgInstructionsAdded = String(format: "%.2f", stub.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) - let invocationSuccessRate = Self.percentageOrNa(stub.invocationSuccessRate, 6) + let avgInstructionsAdded = String( + format: "%.2f", stub.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) + let invocationSuccessRate = Self.percentageOrNa( + stub.invocationSuccessRate, 6) let samplesGenerated = stub.totalSamples - self.logger.verbose(" \(name) : Invocation Success: \(invocationSuccessRate), Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)") + self.logger.verbose( + " \(name) : Invocation Success: \(invocationSuccessRate), Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)" + ) } } } diff --git a/Sources/Fuzzilli/Modules/Storage.swift b/Sources/Fuzzilli/Modules/Storage.swift index 72c5ad49f..9d3d08afa 100644 --- a/Sources/Fuzzilli/Modules/Storage.swift +++ b/Sources/Fuzzilli/Modules/Storage.swift @@ -56,22 +56,34 @@ public class Storage: Module { public func initialize(with fuzzer: Fuzzer) { do { - try FileManager.default.createDirectory(atPath: crashesDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: duplicateCrashesDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: differentialsDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: corpusDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: statisticsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: crashesDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: duplicateCrashesDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: differentialsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: corpusDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: statisticsDir, withIntermediateDirectories: true) if fuzzer.config.enableDiagnostics { - try FileManager.default.createDirectory(atPath: failedDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: timeOutDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: diagnosticsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: failedDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: timeOutDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: diagnosticsDir, withIntermediateDirectories: true) } if fuzzer.isDifferentialFuzzing { - try FileManager.default.createDirectory(atPath: optimizedDumpDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: unoptimizedDumpDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: optimizedDumpDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: unoptimizedDumpDir, withIntermediateDirectories: true) } } catch { - logger.fatal("Failed to create storage directories. Is \(storageDir) writable by the current user?") + logger.fatal( + "Failed to create storage directories. Is \(storageDir) writable by the current user?" + ) } struct Settings: Codable { @@ -80,7 +92,8 @@ public class Storage: Module { } // Write the current settings to disk. - let settings = Settings(processArguments: Array(fuzzer.runner.processArguments[1...]), tag: fuzzer.config.tag) + let settings = Settings( + processArguments: Array(fuzzer.runner.processArguments[1...]), tag: fuzzer.config.tag) var settingsData: Data? do { let encoder = JSONEncoder() @@ -94,7 +107,8 @@ public class Storage: Module { let settingsUrl = URL(fileURLWithPath: "\(self.storageDir)/settings.json") try settingsData!.write(to: settingsUrl) } catch { - logger.fatal("Failed to write settings to disk. Is \(storageDir) writable by the current user?") + logger.fatal( + "Failed to write settings to disk. Is \(storageDir) writable by the current user?") } fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in @@ -140,7 +154,9 @@ public class Storage: Module { logger.fatal("Requested stats export but no Statistics module is active") } fuzzer.timers.scheduleTask(every: interval) { self.saveStatistics(stats) } - fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in self.saveStatistics(stats) } + fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in + self.saveStatistics(stats) + } } } @@ -209,7 +225,8 @@ public class Storage: Module { let date = formatDate() let statsUrl = URL(fileURLWithPath: "\(self.statisticsDir)/\(date).json") try statsData.write(to: statsUrl) - let evaluatorStateUrl = URL(fileURLWithPath: "\(self.statisticsDir)/\(date)_evaluator_state.bin") + let evaluatorStateUrl = URL( + fileURLWithPath: "\(self.statisticsDir)/\(date)_evaluator_state.bin") try evaluatorStateData.write(to: evaluatorStateUrl) } catch { diff --git a/Sources/Fuzzilli/Modules/Sync.swift b/Sources/Fuzzilli/Modules/Sync.swift index f09db6bd1..d21b68d8c 100644 --- a/Sources/Fuzzilli/Modules/Sync.swift +++ b/Sources/Fuzzilli/Modules/Sync.swift @@ -59,30 +59,30 @@ import Foundation /// The different messages supported by the distributed fuzzing protocol. enum MessageType: UInt32 { // Informs the other side that the sender is terminating. - case shutdown = 0 + case shutdown = 0 // A synchronization packet sent by a parent to a newly connected child. // Contains the exported state of the parent so the child can // synchronize itself with that. - case sync = 1 + case sync = 1 // A program from a corpus import. Send from parents to children. // Children are expected to add this program to their corpus // even if it does not trigger new coverage and without minimization. - case importedProgram = 2 + case importedProgram = 2 // A program that triggered interesting behaviour and which should // therefore be imported by the receiver. - case interestingProgram = 3 + case interestingProgram = 3 // A program that caused a crash. Only sent from a children to their parent. - case crashingProgram = 4 + case crashingProgram = 4 // A statistics package send by a child to a parent node. - case statistics = 5 + case statistics = 5 // Log messages are forwarded from child to parent nides. - case log = 6 + case log = 6 } /// Distributed fuzzing nodes can be configured to only share their corpus in one direction in the tree. @@ -161,7 +161,9 @@ public class DistributedFuzzingNode { // If the wasm enablement is different, we can't safely import the corpus. let parentState = fuzzer.config.isWasmEnabled ? "enabled" : "disabled" let selfState = state.isWasmEnabled ? "enabled" : "disabled" - throw FuzzilliError.corpusImportError("Inconsistent state between distributed nodes: The parent has wasm \(parentState) while the current fuzzer has wasm \(selfState)!") + throw FuzzilliError.corpusImportError( + "Inconsistent state between distributed nodes: The parent has wasm \(parentState) while the current fuzzer has wasm \(selfState)!" + ) } try fuzzer.corpus.importState(state.corpus) @@ -191,7 +193,10 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { /// List of all child nodes connected to us. They are identified by their UUID. private var children = Set() - init(for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, transport: DistributedFuzzingParentNodeTransport) { + init( + for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, + transport: DistributedFuzzingParentNodeTransport + ) { self.transport = transport super.init(for: fuzzer, name: name, corpusSynchronizationMode: corpusSynchronizationMode) transport.setOnMessageCallback(onMessageReceived) @@ -205,7 +210,8 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in let shutdownGroup = DispatchGroup() for child in self.children { - self.transport.send(.shutdown, to: child, contents: Data(), synchronizeWith: shutdownGroup) + self.transport.send( + .shutdown, to: child, contents: Data(), synchronizeWith: shutdownGroup) } // Attempt to make sure that the shutdown messages have been sent before continuing. let _ = shutdownGroup.wait(timeout: .now() + .seconds(5)) @@ -254,7 +260,9 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { case .interestingProgram: guard shouldAcceptCorpusSamplesFromChildren() else { - logger.warning("Received corpus sample from child node but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message.") + logger.warning( + "Received corpus sample from child node but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message." + ) return } @@ -277,15 +285,19 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { case .log: if let proto = try? Fuzzilli_Protobuf_LogMessage(serializedBytes: data), - let origin = UUID(uuidString: proto.origin), - let level = LogLevel(rawValue: Int(clamping: proto.level)) { - fuzzer.dispatchEvent(fuzzer.events.Log, data: (origin: origin, level: level, label: proto.label, message: proto.content)) + let origin = UUID(uuidString: proto.origin), + let level = LogLevel(rawValue: Int(clamping: proto.level)) + { + fuzzer.dispatchEvent( + fuzzer.events.Log, + data: (origin: origin, level: level, label: proto.label, message: proto.content) + ) } else { logger.warning("Received malformed log message from child node") } case .importedProgram, - .sync: + .sync: logger.error("Received unexpected message: \(messageType)") } @@ -316,7 +328,9 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { } let (state, duration) = measureTime { exportState() } - logger.info("Encoding fuzzer state took \((String(format: "%.2f", duration)))s. Data size: \(ByteCountFormatter.string(fromByteCount: Int64(state.count), countStyle: .memory))") + logger.info( + "Encoding fuzzer state took \((String(format: "%.2f", duration)))s. Data size: \(ByteCountFormatter.string(fromByteCount: Int64(state.count), countStyle: .memory))" + ) transport.send(.sync, to: child, contents: state) } @@ -333,14 +347,15 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { protocol DistributedFuzzingParentNodeTransport { func initialize() func send(_ messageType: MessageType, to child: UUID, contents: Data) - func send(_ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith: DispatchGroup) + func send( + _ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith: DispatchGroup) func disconnect(_ child: UUID) - typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data, _ child: UUID) -> () + typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data, _ child: UUID) -> Void func setOnMessageCallback(_ callback: @escaping OnMessageCallback) - typealias OnChildConnectedCallback = (_ child: UUID) -> () + typealias OnChildConnectedCallback = (_ child: UUID) -> Void func setOnChildConnectedCallback(_ callback: @escaping OnChildConnectedCallback) - typealias OnChildDisconnectedCallback = (_ child: UUID) -> () + typealias OnChildDisconnectedCallback = (_ child: UUID) -> Void func setOnChildDisconnectedCallback(_ callback: @escaping OnChildDisconnectedCallback) } @@ -353,7 +368,10 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { private let transport: DistributedFuzzingChildNodeTransport private var parentIsShuttingDown = false - init(for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, transport: DistributedFuzzingChildNodeTransport) { + init( + for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, + transport: DistributedFuzzingChildNodeTransport + ) { self.transport = transport super.init(for: fuzzer, name: name, corpusSynchronizationMode: corpusSynchronizationMode) transport.setOnMessageCallback(onMessageReceived) @@ -427,14 +445,18 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { guard shouldAcceptCorpusSamplesFromParent() else { return } guard !data.isEmpty else { - return logger.warning("Received empty synchronization message. Is the parent node configured to synchronize its corpus with its children?") + return logger.warning( + "Received empty synchronization message. Is the parent node configured to synchronize its corpus with its children?" + ) } guard fuzzer.state == .waiting else { // While child nodes will remain in the .waiting state until we've received a sync message, this can // still legitimately happen, for example if we imported our own corpus, or if we've lost the connection // to our parent node and are reconnecting to it. - return logger.info("Not synchronizing our state with that of our parent as we already have a corpus") + return logger.info( + "Not synchronizing our state with that of our parent as we already have a corpus" + ) } let start = Date() @@ -444,12 +466,16 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { logger.error("Failed to synchronize state: \(error)") } let end = Date() - logger.info("Synchronized with parent node (took \((String(format: "%.2f", end.timeIntervalSince(start))))s). Corpus now contains \(fuzzer.corpus.size) programs") + logger.info( + "Synchronized with parent node (took \((String(format: "%.2f", end.timeIntervalSince(start))))s). Corpus now contains \(fuzzer.corpus.size) programs" + ) case .importedProgram, - .interestingProgram: + .interestingProgram: guard shouldAcceptCorpusSamplesFromParent() else { - return logger.warning("Received corpus sample but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message.") + return logger.warning( + "Received corpus sample but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message." + ) } do { @@ -460,7 +486,8 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { // Regardless of the corpus import mode used by the parent node, as a child node we // always add the program to our corpus without further checks or minimization as // that will, if necessary, already have been performed by our parent node. - fuzzer.importProgram(program, origin: .corpusImport(mode: .full), enableDropout: true) + fuzzer.importProgram( + program, origin: .corpusImport(mode: .full), enableDropout: true) } else { assert(messageType == .interestingProgram) fuzzer.importProgram(program, origin: .parent, enableDropout: true) @@ -470,8 +497,8 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { } case .crashingProgram, - .statistics, - .log: + .statistics, + .log: logger.error("Received unexpected message: \(messageType)") } } @@ -508,6 +535,6 @@ protocol DistributedFuzzingChildNodeTransport { func send(_ messageType: MessageType, contents: Data) func send(_ messageType: MessageType, contents: Data, synchronizeWith: DispatchGroup) - typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data) -> () + typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data) -> Void func setOnMessageCallback(_ callback: @escaping OnMessageCallback) } diff --git a/Sources/Fuzzilli/Modules/ThreadSync.swift b/Sources/Fuzzilli/Modules/ThreadSync.swift index fd2c226d4..f77fb967b 100644 --- a/Sources/Fuzzilli/Modules/ThreadSync.swift +++ b/Sources/Fuzzilli/Modules/ThreadSync.swift @@ -23,7 +23,9 @@ public class ThreadParent: DistributedFuzzingParentNode { public init(for fuzzer: Fuzzer) { self.transport = Transport(for: fuzzer) - super.init(for: fuzzer, name: "ThreadParent", corpusSynchronizationMode: .full, transport: transport) + super.init( + for: fuzzer, name: "ThreadParent", corpusSynchronizationMode: .full, + transport: transport) } fileprivate class Transport: DistributedFuzzingParentNodeTransport { @@ -70,12 +72,17 @@ public class ThreadParent: DistributedFuzzingParentNode { fatalError("Unknown child node \(child)") } client.async { - guard let module = ThreadChild.instance(for: client) else { fatalError("No active ThreadChild module on client instance") } + guard let module = ThreadChild.instance(for: client) else { + fatalError("No active ThreadChild module on client instance") + } module.transport.onMessageCallback?(messageType, contents) } } - func send(_ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith synchronizationGroup: DispatchGroup) { + func send( + _ messageType: MessageType, to child: UUID, contents: Data, + synchronizeWith synchronizationGroup: DispatchGroup + ) { send(messageType, to: child, contents: contents) } @@ -106,7 +113,9 @@ public class ThreadChild: DistributedFuzzingChildNode { public init(for fuzzer: Fuzzer, parent: Fuzzer) { self.transport = Transport(child: fuzzer, parent: parent) - super.init(for: fuzzer, name: "ThreadChild", corpusSynchronizationMode: .full, transport: transport) + super.init( + for: fuzzer, name: "ThreadChild", corpusSynchronizationMode: .full, transport: transport + ) } fileprivate class Transport: DistributedFuzzingChildNodeTransport { diff --git a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift index 4ad73bccb..4cd2d2543 100644 --- a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift +++ b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift @@ -21,7 +21,9 @@ public class BaseInstructionMutator: Mutator { super.init(name: name) } - override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { beginMutation(of: program) var candidates = [Int]() @@ -40,7 +42,7 @@ public class BaseInstructionMutator: Mutator { toMutate.insert(chooseUniform(from: candidates)) } - b.adopting() { + b.adopting { for instr in program.code { if toMutate.contains(instr.index) { mutate(instr, b) @@ -68,4 +70,3 @@ public class BaseInstructionMutator: Mutator { fatalError("This method must be overridden") } } - diff --git a/Sources/Fuzzilli/Mutators/CodeGenMutator.swift b/Sources/Fuzzilli/Mutators/CodeGenMutator.swift index 0536540f3..4326e4fa3 100644 --- a/Sources/Fuzzilli/Mutators/CodeGenMutator.swift +++ b/Sources/Fuzzilli/Mutators/CodeGenMutator.swift @@ -36,11 +36,14 @@ public class CodeGenMutator: BaseInstructionMutator { // Don't CodeGen on Type definition instructions, with this line they are not available as candidates which effectively compresses the program and avoids useless CodeGeneration. // (As any emitted type would not be an input to the EndTypeGroup instruction). - if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) || (instr.op is WasmBeginTypeGroup) { + if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) + || (instr.op is WasmBeginTypeGroup) + { return false } - return variableAnalyzer.visibleVariables.count >= minVisibleVariables && !deadCodeAnalyzer.currentlyInDeadCode + return variableAnalyzer.visibleVariables.count >= minVisibleVariables + && !deadCodeAnalyzer.currentlyInDeadCode } public override func mutate(_ instr: Instruction, _ b: ProgramBuilder) { diff --git a/Sources/Fuzzilli/Mutators/ConcatMutator.swift b/Sources/Fuzzilli/Mutators/ConcatMutator.swift index 00a8f6fb9..0958eb38d 100644 --- a/Sources/Fuzzilli/Mutators/ConcatMutator.swift +++ b/Sources/Fuzzilli/Mutators/ConcatMutator.swift @@ -14,7 +14,9 @@ /// A mutator that concatenates two programs together. public class ConcatMutator: Mutator { - override func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { let suffix = b.fuzzer.corpus.randomElementForSplicing() b.append(program) diff --git a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift index 24e6a9551..048ed446e 100644 --- a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift +++ b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift @@ -83,7 +83,8 @@ public class ExplorationMutator: RuntimeAssistedMutator { let numUntypedVariablesToExplore = Int((Double(untypedVariables.count) * 0.5).rounded(.up)) // TODO probably we only rarely want to explore known variables (e.g. only 10% of them or even fewer). But currently, the JSTyper and JavaScriptEnvironment still often set the type to something like .object() or so, which isn't very useful (it's basically a "unknownObject" type). We should maybe stop doing that... let numTypedVariablesToExplore = Int((Double(typedVariables.count) * 0.25).rounded(.up)) - let untypedVariablesToExplore = untypedVariables.shuffled().prefix(numUntypedVariablesToExplore) + let untypedVariablesToExplore = untypedVariables.shuffled().prefix( + numUntypedVariablesToExplore) let typedVariablesToExplore = typedVariables.shuffled().prefix(numTypedVariablesToExplore) let variablesToExplore = VariableSet(untypedVariablesToExplore + typedVariablesToExplore) guard !variablesToExplore.isEmpty else { @@ -106,7 +107,7 @@ public class ExplorationMutator: RuntimeAssistedMutator { // For that reason, we keep a stack of variables that still need to be explored. A variable in that stack is explored // when its entry is popped from the stack, which happens when the block end instruction is emitted. var pendingExploreStack = Stack() - b.adopting() { + b.adopting { for instr in program.code { b.adopt(instr) @@ -145,7 +146,10 @@ public class ExplorationMutator: RuntimeAssistedMutator { return instrumentedProgram } - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { // Initialize the actions dictionary that will contain the processed results. // This way, we can detect if something went wrong on the JS side: if we get results for IDs // for which there is no Explore operation, then there's probably a bug in the JS code. @@ -205,20 +209,25 @@ public class ExplorationMutator: RuntimeAssistedMutator { } // Now build the real program by replacing every Explore operation with the operation(s) that it actually performed at runtime. - b.adopting() { + b.adopting { for instr in instrumentedProgram.code { if let op = instr.op as? Explore { if let entry = actions[op.id], let action = entry { if verbose { actionUsageCounts[action.operation]! += 1 } let exploredValue = b.adopt(instr.input(0)) let args = instr.inputs.suffix(from: 1).map(b.adopt) - guard case .special(let name) = action.inputs.first, name == "exploredValue" else { - logger.error("Unexpected first input, expected the explored value, got \(String(describing: action.inputs.first)) for operation \(action.operation)") + guard case .special(let name) = action.inputs.first, name == "exploredValue" + else { + logger.error( + "Unexpected first input, expected the explored value, got \(String(describing: action.inputs.first)) for operation \(action.operation)" + ) continue } b.trace("Exploring value \(exploredValue)") do { - let context = (arguments: args, specialValues: ["exploredValue": exploredValue]) + let context = ( + arguments: args, specialValues: ["exploredValue": exploredValue] + ) try action.translateToFuzzIL(withContext: context, using: b) } catch ActionError.actionTranslationError(let msg) { logger.error("Failed to process action: \(msg)") @@ -238,12 +247,16 @@ public class ExplorationMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average number of inserted explore operations: \(String(format: "%.2f", averageNumberOfInsertedExploreOps.currentValue))") + logger.verbose( + "Average number of inserted explore operations: \(String(format: "%.2f", averageNumberOfInsertedExploreOps.currentValue))" + ) let totalHandlerInvocations = actionUsageCounts.values.reduce(0, +) logger.verbose("Frequencies of generated operations:") for (op, count) in actionUsageCounts { let frequency = (Double(count) / Double(totalHandlerInvocations)) * 100.0 - logger.verbose(" \(op.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f", frequency))%") + logger.verbose( + " \(op.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f", frequency))%" + ) } } } diff --git a/Sources/Fuzzilli/Mutators/FixupMutator.swift b/Sources/Fuzzilli/Mutators/FixupMutator.swift index fc9865bed..42da2a1f2 100644 --- a/Sources/Fuzzilli/Mutators/FixupMutator.swift +++ b/Sources/Fuzzilli/Mutators/FixupMutator.swift @@ -64,10 +64,20 @@ public class FixupMutator: RuntimeAssistedMutator { // Helper functions to emit the Fixup operations. var numInstrumentedInstructions = 0 let actionEncoder = JSONEncoder() - func fixup(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func fixup( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { assert(instr.numOutputs == 0 || instr.numOutputs == 1) assert(instr.numInnerOutputs == 0) - assert(inputs.allSatisfy({ if case .argument(let index) = $0 { return index < instr.numInputs } else { return true }})) + assert( + inputs.allSatisfy({ + if case .argument(let index) = $0 { + return index < instr.numInputs + } else { + return true + } + })) numInstrumentedInstructions += 1 @@ -75,19 +85,26 @@ public class FixupMutator: RuntimeAssistedMutator { let action = Action(id: id, operation: op, inputs: inputs, isGuarded: guarded) let encodedData = try! actionEncoder.encode(action) let encodedAction = String(data: encodedData, encoding: .utf8)! - let maybeOutput = b.fixup(id: id, action: encodedAction, originalOperation: instr.op.name, arguments: Array(instr.inputs), hasOutput: instr.hasOneOutput) + let maybeOutput = b.fixup( + id: id, action: encodedAction, originalOperation: instr.op.name, + arguments: Array(instr.inputs), hasOutput: instr.hasOneOutput) // The fixup instruction must create the same output variable, as that may be used by subsequent code. assert(!instr.hasOutputs || instr.output == maybeOutput) if verbose { - instrumentedOperations[instr.op.name] = (instrumentedOperations[instr.op.name] ?? 0) + 1 + instrumentedOperations[instr.op.name] = + (instrumentedOperations[instr.op.name] ?? 0) + 1 if instr.isGuarded { - instrumentedGuardedOperations[instr.op.name] = (instrumentedGuardedOperations[instr.op.name] ?? 0) + 1 + instrumentedGuardedOperations[instr.op.name] = + (instrumentedGuardedOperations[instr.op.name] ?? 0) + 1 } } } - func maybeFixup(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func maybeFixup( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { // Only instrument some percentage of unguarded instructions but do still instrument all guarded instructions (to attempt to remove the guards). if !guarded { if !probability(probabilityOfFixingUnguardedInstruction) { @@ -99,7 +116,10 @@ public class FixupMutator: RuntimeAssistedMutator { fixup(instr, performing: op, guarded: guarded, withInputs: inputs, with: b) } - func fixupIfGuarded(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func fixupIfGuarded( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { guard guarded else { b.append(instr) return @@ -116,55 +136,80 @@ public class FixupMutator: RuntimeAssistedMutator { // exception would be raised. case .callFunction(let op): let inputs = (0.. (Program?, RuntimeAssistedMutator.Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, RuntimeAssistedMutator.Outcome) { // For each Fixup operation (identified by its Id), this dict contains the (potentially modified) action that was performed by it. var actions = [String: Action]() @@ -191,7 +239,10 @@ public class FixupMutator: RuntimeAssistedMutator { // Populate the actions map with the original actions. This way, we can verify that the received (updated) actions all belong to a Fixup operation. for instr in instrumentedProgram.code { if let op = instr.op as? Fixup { - guard let originalAction = try? actionDecoder.decode(Action.self, from: op.action.data(using: .utf8)!) else { + guard + let originalAction = try? actionDecoder.decode( + Action.self, from: op.action.data(using: .utf8)!) + else { logger.error("Failed to decode original action \"\(op.action)\"") return (nil, .unexpectedError) } @@ -233,7 +284,9 @@ public class FixupMutator: RuntimeAssistedMutator { } seenFailures.insert(id) // We could also drop this action or replace it with a different one, but for now, simply add the guard back if we observe a failure. - actions[id] = Action(id: action.id, operation: action.operation, inputs: action.inputs, isGuarded: true) + actions[id] = Action( + id: action.id, operation: action.operation, inputs: action.inputs, + isGuarded: true) } else if line.hasPrefix(actionMarker) { let payload = Data(line.dropFirst(actionMarker.count).utf8) guard let action = try? actionDecoder.decode(Action.self, from: payload) else { @@ -283,9 +336,10 @@ public class FixupMutator: RuntimeAssistedMutator { let args = Array(instr.inputs) b.trace("Fixing next instruction") do { - try action.translateToFuzzIL(withContext: (arguments: args, specialValues: [:]), using: b) + try action.translateToFuzzIL( + withContext: (arguments: args, specialValues: [:]), using: b) assert(!op.hasOutput || b.visibleVariables.last == instr.output) - assert(op.originalOperation == b.lastInstruction().op.name) // We expect the old and new operations to be the same (but potentially performed on different inputs) + assert(op.originalOperation == b.lastInstruction().op.name) // We expect the old and new operations to be the same (but potentially performed on different inputs) } catch ActionError.actionTranslationError(let msg) { // In case of an error we won't have emitted an instruction. As such, we need // to abort the mutation here (unfortunately), as we might now have an @@ -302,7 +356,8 @@ public class FixupMutator: RuntimeAssistedMutator { } b.trace("Fixup done") if verbose && modifiedActions.contains(action.id) { - modifiedOperations[op.originalOperation] = (modifiedOperations[op.originalOperation] ?? 0) + 1 + modifiedOperations[op.originalOperation] = + (modifiedOperations[op.originalOperation] ?? 0) + 1 } } else { b.append(instr) @@ -314,13 +369,19 @@ public class FixupMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average success rate (percentage of removed guards) during recent mutations: \(String(format: "%.2f", averageSuccesRate.currentValue * 100))%") - logger.verbose("Average percentage of instrumented instructions: \(String(format: "%.2f", averageInstrumentationRatio.currentValue * 100))%") + logger.verbose( + "Average success rate (percentage of removed guards) during recent mutations: \(String(format: "%.2f", averageSuccesRate.currentValue * 100))%" + ) + logger.verbose( + "Average percentage of instrumented instructions: \(String(format: "%.2f", averageInstrumentationRatio.currentValue * 100))%" + ) logger.verbose("Per-operation statistics:") for (opName, count) in instrumentedOperations { let guardedRatio = Double(instrumentedGuardedOperations[opName] ?? 0) / Double(count) let modificationRate = Double(modifiedOperations[opName] ?? 0) / Double(count) - logger.verbose(" \(opName.rightPadded(toLength: 30)): instrumented \(count) times (of which \(String(format: "%.2f", guardedRatio * 100))% were guarded), modification rate: \(String(format: "%.2f", modificationRate * 100))%") + logger.verbose( + " \(opName.rightPadded(toLength: 30)): instrumented \(count) times (of which \(String(format: "%.2f", guardedRatio * 100))% were guarded), modification rate: \(String(format: "%.2f", modificationRate * 100))%" + ) } } } diff --git a/Sources/Fuzzilli/Mutators/InputMutator.swift b/Sources/Fuzzilli/Mutators/InputMutator.swift index 7f03a9ffc..01c214a89 100644 --- a/Sources/Fuzzilli/Mutators/InputMutator.swift +++ b/Sources/Fuzzilli/Mutators/InputMutator.swift @@ -34,11 +34,13 @@ public class InputMutator: BaseInstructionMutator { // the mutator correctness rates, it can very roughly be twice as aggressive. switch self.typeAwareness { case .aware: - maxSimultaneousMutations *= 2 + maxSimultaneousMutations *= 2 default: break } - super.init(name: "InputMutator (\(String(describing: self.typeAwareness)))", maxSimultaneousMutations: maxSimultaneousMutations) + super.init( + name: "InputMutator (\(String(describing: self.typeAwareness)))", + maxSimultaneousMutations: maxSimultaneousMutations) } public override func canMutate(_ instr: Instruction) -> Bool { @@ -62,14 +64,15 @@ public class InputMutator: BaseInstructionMutator { let replacement: Variable? // In wasm we need strict typing, so there is no notion of loose or aware. - if b.context.contains(.wasm) || - b.context.contains(.wasmFunction) || - b.context.contains(.wasmTypeGroup) { + if b.context.contains(.wasm) || b.context.contains(.wasmFunction) + || b.context.contains(.wasmTypeGroup) + { let type = b.type(of: inouts[selectedInput]) // TODO(mliedtke): For type definitions we need a lot of consistency. E.g. the signature // flowing into the block begin operation and the block end operation need to be in // sync. - replacement = type.Is(.wasmTypeDef()) ? inouts[selectedInput] : b.randomVariable(ofType: type) + replacement = + type.Is(.wasmTypeDef()) ? inouts[selectedInput] : b.randomVariable(ofType: type) } else { switch self.typeAwareness { case .loose: @@ -81,7 +84,8 @@ public class InputMutator: BaseInstructionMutator { } if let replacement = replacement { - b.trace("Replacing input \(selectedInput) (\(inouts[selectedInput])) with \(replacement)") + b.trace( + "Replacing input \(selectedInput) (\(inouts[selectedInput])) with \(replacement)") inouts[selectedInput] = replacement // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. diff --git a/Sources/Fuzzilli/Mutators/MutatorSettings.swift b/Sources/Fuzzilli/Mutators/MutatorSettings.swift index f080de7d8..b08983493 100644 --- a/Sources/Fuzzilli/Mutators/MutatorSettings.swift +++ b/Sources/Fuzzilli/Mutators/MutatorSettings.swift @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. - // The settings here strive to achieve a correctness rate of around 75%. Empirically, this appears to be roughly optimal: // higher than that, and samples are too similar to each other, lower than that, and too many samples are invalid. // TODO evaluate this independently for every mutator. let defaultMaxSimultaneousMutations = 7 let defaultMaxSimultaneousCodeGenerations = 3 -let defaultCodeGenerationAmount = 5 // This must be at least ProgramBuilder.minBudgetForRecursiveCodeGeneration +let defaultCodeGenerationAmount = 5 // This must be at least ProgramBuilder.minBudgetForRecursiveCodeGeneration diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4d7903629..c7614ff25 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -30,7 +30,8 @@ public class OperationMutator: BaseInstructionMutator { let newInstr: Instruction if instr.isOperationMutable && instr.isVariadic { - newInstr = probability(0.5) ? mutateOperation(instr, b) : extendVariadicOperation(instr, b) + newInstr = + probability(0.5) ? mutateOperation(instr, b) : extendVariadicOperation(instr, b) } else if instr.isOperationMutable { newInstr = mutateOperation(instr, b) } else { @@ -55,19 +56,24 @@ public class OperationMutator: BaseInstructionMutator { // Half the time we want to just hit the regular path if Bool.random() { if let type = b.fuzzer.environment.getEnum(ofName: customName) { - newOp = LoadString(value: chooseUniform(from: type.enumValues), customName: customName) + newOp = LoadString( + value: chooseUniform(from: type.enumValues), customName: customName) break - } else if let gen = b.fuzzer.environment.getNamedStringGenerator(ofName: customName) { + } else if let gen = b.fuzzer.environment.getNamedStringGenerator( + ofName: customName) + { newOp = LoadString(value: gen(), customName: customName) break } } } - let charSetAlNum = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + let charSetAlNum = Array( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") // TODO(mliedtke): Should we also use some more esoteric characters in initial string // creation, e.g. ProgramBuilder.randomString? - let charSetExtended = charSetAlNum + Array("-_.,!?<>()[]{}`´^\\/|+#*=;:'~^²\t°ß¿ 🤯🙌🏿\u{202D}") - let randomIndex = {(s: String) in + let charSetExtended = + charSetAlNum + Array("-_.,!?<>()[]{}`´^\\/|+#*=;:'~^²\t°ß¿ 🤯🙌🏿\u{202D}") + let randomIndex = { (s: String) in s.index(s.startIndex, offsetBy: Int.random(in: 0.. Instruction { + private func extendVariadicOperationByOneInput(_ instr: Instruction, _ b: ProgramBuilder) + -> Instruction + { // Without visible variables, we can't add a new input to this instruction. // This should happen rarely, so just skip this mutation. guard b.hasVisibleVariables else { return instr } @@ -777,28 +873,35 @@ public class OperationMutator: BaseInstructionMutator { case .callFunctionWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallFunctionWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallFunctionWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .construct(let op): inputs.append(b.randomJsVariable()) newOp = Construct(numArguments: op.numArguments + 1, isGuarded: op.isGuarded) case .constructWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = ConstructWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = ConstructWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .callMethod(let op): inputs.append(b.randomJsVariable()) - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments + 1, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments + 1, + isGuarded: op.isGuarded) case .callMethodWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments + 1, spreads: spreads, + isGuarded: op.isGuarded) case .callComputedMethod(let op): inputs.append(b.randomJsVariable()) newOp = CallComputedMethod(numArguments: op.numArguments + 1, isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallComputedMethodWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallComputedMethodWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .callSuperConstructor(let op): inputs.append(b.randomJsVariable()) newOp = CallSuperConstructor(numArguments: op.numArguments + 1) @@ -834,7 +937,9 @@ public class OperationMutator: BaseInstructionMutator { return Instruction(newOp, inouts: inouts, flags: .empty) } - private func replaceRandomElement(in elements: inout Array, generatingRandomValuesWith generator: () -> T) { + private func replaceRandomElement( + in elements: inout [T], generatingRandomValuesWith generator: () -> T + ) { // Pick a random index to replace. guard let index = elements.indices.randomElement() else { return } diff --git a/Sources/Fuzzilli/Mutators/ProbingMutator.swift b/Sources/Fuzzilli/Mutators/ProbingMutator.swift index de3aaba09..f7c29f2ed 100644 --- a/Sources/Fuzzilli/Mutators/ProbingMutator.swift +++ b/Sources/Fuzzilli/Mutators/ProbingMutator.swift @@ -75,7 +75,7 @@ public class ProbingMutator: RuntimeAssistedMutator { // the block that they are the output of is closed. var pendingProbesStack = Stack() let b = fuzzer.makeBuilder() - b.adopting() { + b.adopting { for instr in program.code { b.adopt(instr) @@ -106,7 +106,10 @@ public class ProbingMutator: RuntimeAssistedMutator { return instrumentedProgram } - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, RuntimeAssistedMutator.Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, RuntimeAssistedMutator.Outcome) { assert(instrumentedProgram.code.contains(where: { $0.op is Probe })) // Parse the output: look for either "PROBING_ERROR" or "PROBING_RESULTS" and process the content. @@ -130,7 +133,8 @@ public class ProbingMutator: RuntimeAssistedMutator { let decoder = JSONDecoder() let payload = Data(line.dropFirst(resultsMarker.count).utf8) - guard let decodedResults = try? decoder.decode([String: Result].self, from: payload) else { + guard let decodedResults = try? decoder.decode([String: Result].self, from: payload) + else { logger.error("Failed to decode JSON payload in \"\(line)\"") return (nil, .unexpectedError) } @@ -143,7 +147,7 @@ public class ProbingMutator: RuntimeAssistedMutator { // Now build the final program by parsing the results and replacing the Probe operations // with FuzzIL operations that install one of the non-existent properties (if any). - b.adopting() { + b.adopting { for instr in instrumentedProgram.code { if let op = instr.op as? Probe { if let results = results[op.id] { @@ -162,10 +166,13 @@ public class ProbingMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average number of inserted probes: \(String(format: "%.2f", averageNumberOfInsertedProbes.currentValue))") - logger.verbose("Properties installed during recent mutations (in total: \(installedPropertyCounter)):") + logger.verbose( + "Average number of inserted probes: \(String(format: "%.2f", averageNumberOfInsertedProbes.currentValue))" + ) + logger.verbose( + "Properties installed during recent mutations (in total: \(installedPropertyCounter)):") var statsAsList = installedPropertiesForGetAccess.map({ (key: $0, count: $1, op: "get") }) - statsAsList += installedPropertiesForSetAccess.map({ (key: $0, count: $1, op: "set") }) + statsAsList += installedPropertiesForSetAccess.map({ (key: $0, count: $1, op: "set") }) for (key, count, op) in statsAsList.sorted(by: { $0.count > $1.count }) { let type = isCallableProperty(key) ? "function" : "anything" logger.verbose(" \(count)x \(key.description) (access: \(op), type: \(type))") @@ -178,7 +185,10 @@ public class ProbingMutator: RuntimeAssistedMutator { private func processProbeResults(_ result: Result, on obj: Variable, using b: ProgramBuilder) { // Extract all candidates: properties that are accessed but not present (or explicitly marked as overwritable). - let loadCandidates = result.loads.filter({ $0.value == .notFound || ($0.value == .found && propertiesOnPrototypeToOverwrite.contains($0.key)) }).map({ $0.key }) + let loadCandidates = result.loads.filter({ + $0.value == .notFound + || ($0.value == .found && propertiesOnPrototypeToOverwrite.contains($0.key)) + }).map({ $0.key }) // For stores we only care about properties that don't exist anywhere on the prototype chain. let storeCandidates = result.stores.filter({ $0.value == .notFound }).map({ $0.key }) let candidates = Set(loadCandidates).union(storeCandidates) @@ -194,20 +204,26 @@ public class ProbingMutator: RuntimeAssistedMutator { if probability(0.8) { installRegularProperty(property, on: obj, using: b) } else { - installPropertyAccessor(for: property, on: obj, using: b, shouldHaveGetter: propertyIsLoaded, shouldHaveSetter: propertyIsStored) + installPropertyAccessor( + for: property, on: obj, using: b, shouldHaveGetter: propertyIsLoaded, + shouldHaveSetter: propertyIsStored) } // Update our statistics. if verbose && propertyIsLoaded { - installedPropertiesForGetAccess[property] = (installedPropertiesForGetAccess[property] ?? 0) + 1 + installedPropertiesForGetAccess[property] = + (installedPropertiesForGetAccess[property] ?? 0) + 1 } if verbose && propertyIsStored { - installedPropertiesForSetAccess[property] = (installedPropertiesForSetAccess[property] ?? 0) + 1 + installedPropertiesForSetAccess[property] = + (installedPropertiesForSetAccess[property] ?? 0) + 1 } installedPropertyCounter += 1 } - private func installRegularProperty(_ property: Property, on obj: Variable, using b: ProgramBuilder) { + private func installRegularProperty( + _ property: Property, on obj: Variable, using b: ProgramBuilder + ) { let value = selectValue(for: property, using: b) switch property { @@ -222,7 +238,10 @@ public class ProbingMutator: RuntimeAssistedMutator { } } - private func installPropertyAccessor(for property: Property, on obj: Variable, using b: ProgramBuilder, shouldHaveGetter: Bool, shouldHaveSetter: Bool) { + private func installPropertyAccessor( + for property: Property, on obj: Variable, using b: ProgramBuilder, shouldHaveGetter: Bool, + shouldHaveSetter: Bool + ) { assert(shouldHaveGetter || shouldHaveSetter) let installAsValue = probability(0.5) let installGetter = !installAsValue && (shouldHaveGetter || probability(0.5)) @@ -262,7 +281,8 @@ public class ProbingMutator: RuntimeAssistedMutator { case .symbol(let desc): let Symbol = b.createNamedVariable(forBuiltin: "Symbol") let symbol = b.getProperty(extractSymbolNameFromDescription(desc), of: Symbol) - b.configureComputedProperty(symbol, of: obj, usingFlags: PropertyFlags.random(), as: config) + b.configureComputedProperty( + symbol, of: obj, usingFlags: PropertyFlags.random(), as: config) } } @@ -277,8 +297,12 @@ public class ProbingMutator: RuntimeAssistedMutator { } private func isCallableProperty(_ property: Property) -> Bool { - let knownFunctionPropertyNames = ["valueOf", "toString", "constructor", "then", "next", "get", "set"] - let knownNonFunctionSymbolNames = ["Symbol.isConcatSpreadable", "Symbol.unscopables", "Symbol.toStringTag"] + let knownFunctionPropertyNames = [ + "valueOf", "toString", "constructor", "then", "next", "get", "set", + ] + let knownNonFunctionSymbolNames = [ + "Symbol.isConcatSpreadable", "Symbol.unscopables", "Symbol.toStringTag", + ] // Check if the property should be a function. switch property { @@ -295,11 +319,13 @@ public class ProbingMutator: RuntimeAssistedMutator { if isCallableProperty(property) { // Either create a new function or reuse an existing one let probabilityOfReusingExistingFunction = 2.0 / 3.0 - if let f = b.randomVariable(ofType: .function()), probability(probabilityOfReusingExistingFunction) { + if let f = b.randomVariable(ofType: .function()), + probability(probabilityOfReusingExistingFunction) + { return f } else { let f = b.buildPlainFunction(with: .parameters(n: Int.random(in: 0..<3))) { args in - b.build(n: 2) // TODO maybe forbid generating any nested blocks here? + b.build(n: 2) // TODO maybe forbid generating any nested blocks here? b.doReturn(b.randomJsVariable()) } return f diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 4e43be6e0..89845ff39 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -60,13 +60,18 @@ public class RuntimeAssistedMutator: Mutator { } // Process the runtime output of the instrumented program and build the final program from that. - func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { fatalError("Must be overwritten by child classes") } // Helper function for use by child classes. This detects known types of runtime errors that are expected to some degree (e.g. stack exhaustion or OOM). func isKnownRuntimeError(_ message: Substring) -> Bool { - let ignoredErrors = ["maximum call stack size exceeded", "out of memory", "too much recursion"] + let ignoredErrors = [ + "maximum call stack size exceeded", "out of memory", "too much recursion", + ] for error in ignoredErrors { if message.lowercased().contains(error) { return true @@ -80,7 +85,9 @@ public class RuntimeAssistedMutator: Mutator { // May be overwritten by child classes } - override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { // Build the instrumented program. guard let instrumentedProgram = instrument(program, for: fuzzer) else { return failure(.cannotInstrument) @@ -90,7 +97,9 @@ public class RuntimeAssistedMutator: Mutator { assert(instrumentedProgram.code.contains(where: { $0.op is JsInternalOperation })) // Execute the instrumented program (with a higher timeout) and collect the output. - let execution = fuzzer.execute(instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, purpose: .runtimeAssistedMutation) + let execution = fuzzer.execute( + instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, + purpose: .runtimeAssistedMutation) // We need to cache these because they're invalidated the next time we call execute(). let oldStdout = execution.stdout let oldStderr = execution.stderr @@ -118,20 +127,30 @@ public class RuntimeAssistedMutator: Mutator { let stdout = oldFuzzout + "\n" + oldStdout // We log the crash here in case something goes wrong. - let crashInfoText = fuzzer.collectCrashInfo(for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, withExectime: execution.execTime) - logger.error("Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))") + let crashInfoText = fuzzer.collectCrashInfo( + for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, + withExectime: execution.execTime) + logger.error( + "Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))" + ) // Check if the process()'d program also crashes. If yes, we report that crash instead. // This allows to use Fuzzilli's input minimization, which wouldn't work for the instrumented program. - let (mutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (mutatedProgram, outcome) = process( + execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) if let mutatedProgram { assert(outcome == .success) - let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) + let execution = fuzzer.execute( + mutatedProgram, withTimeout: fuzzer.config.timeout, + purpose: .runtimeAssistedMutation) if case .crashed(let signal) = execution.outcome { - logger.warning("Mutated program crashed as well, reporting mutated program instead") + logger.warning( + "Mutated program crashed as well, reporting mutated program instead") let stdout = execution.fuzzout + "\n" + execution.stdout - fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + fuzzer.processCrash( + mutatedProgram, withSignal: signal, withStderr: execution.stderr, + withStdout: stdout, origin: .local, withExectime: execution.execTime) return failure(.instrumentedProgramCrashed) } } @@ -141,26 +160,35 @@ public class RuntimeAssistedMutator: Mutator { // We need this because instrumentation adds boilerplate JS code. let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) var maybeProgramToMinimize: Program? = nil - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".js") - if let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]), - let parser = JavaScriptParser(executor: nodejs) { - do { - try instrumentedJavaScriptProgram.write(to: tempFile, atomically: true, encoding: .utf8) - let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") - } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") - } - try? FileManager.default.removeItem(at: tempFile) + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( + UUID().uuidString + ".js") + if let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]), + let parser = JavaScriptParser(executor: nodejs) + { + do { + try instrumentedJavaScriptProgram.write( + to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") } - else { - logger.warning("Unable to compile instrumented JS program to FuzzIL because node.js is not available") - } - + try? FileManager.default.removeItem(at: tempFile) + } else { + logger.warning( + "Unable to compile instrumented JS program to FuzzIL because node.js is not available" + ) + } - logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") - fuzzer.processCrash(maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + logger.warning( + "Mutated program did not crash, reporting original crash of the instrumented program" + ) + fuzzer.processCrash( + maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, + withStderr: oldStderr, withStdout: stdout, origin: .local, + withExectime: execution.execTime) case .succeeded: // The expected case. break @@ -169,7 +197,8 @@ public class RuntimeAssistedMutator: Mutator { } // Process the output to build the mutated program. - let (maybeMutatedProgram, outcome) = process(oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (maybeMutatedProgram, outcome) = process( + oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) guard let mutatedProgram = maybeMutatedProgram else { assert(outcome != .success) return failure(outcome) @@ -184,7 +213,9 @@ public class RuntimeAssistedMutator: Mutator { for outcome in Outcome.allCases { let count = outcomeCounts[outcome]! let frequency = (Double(count) / Double(totalOutcomes)) * 100.0 - logger.verbose(" \(outcome.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f%%", frequency))") + logger.verbose( + " \(outcome.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f%%", frequency))" + ) } logAdditionalStatistics() @@ -282,11 +313,15 @@ public class RuntimeAssistedMutator: Mutator { } extension RuntimeAssistedMutator.Action.Input { - func translateToFuzzIL(withContext context: (arguments: [Variable], specialValues: [String: Variable]), using b: ProgramBuilder) throws -> Variable { + func translateToFuzzIL( + withContext context: (arguments: [Variable], specialValues: [String: Variable]), + using b: ProgramBuilder + ) throws -> Variable { switch self { case .argument(let index): guard context.arguments.indices.contains(index) else { - throw RuntimeAssistedMutator.ActionError.actionTranslationError("Invalid argument index: \(index), have \(context.arguments.count) arguments") + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Invalid argument index: \(index), have \(context.arguments.count) arguments") } return context.arguments[index] case .int(let value): @@ -295,7 +330,8 @@ extension RuntimeAssistedMutator.Action.Input { return b.loadFloat(value) case .bigint(let value): guard value.allSatisfy({ $0.isNumber || $0 == "-" }) else { - throw RuntimeAssistedMutator.ActionError.actionTranslationError("Malformed bigint value: \(value)") + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Malformed bigint value: \(value)") } if let intValue = Int64(value) { return b.loadBigInt(intValue) @@ -308,17 +344,26 @@ extension RuntimeAssistedMutator.Action.Input { case .string(let value): return b.loadString(value) case .special(let name): - guard let v = context.specialValues[name] else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Unknown special input value \(name)") } + guard let v = context.specialValues[name] else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Unknown special input value \(name)") + } return v } } } extension RuntimeAssistedMutator.Action { - func translateToFuzzIL(withContext context: (arguments: [Variable], specialValues: [String: Variable]), using b: ProgramBuilder) throws { + func translateToFuzzIL( + withContext context: (arguments: [Variable], specialValues: [String: Variable]), + using b: ProgramBuilder + ) throws { // Helper function to fetch an input of this Action. func getInput(_ i: Int) throws -> Input { - guard inputs.indices.contains(i) else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Missing input \(i) for operation \(operation)") } + guard inputs.indices.contains(i) else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Missing input \(i) for operation \(operation)") + } return inputs[i] } // Helper function to fetch an input of this Action and translate it to a FuzzIL variable. @@ -327,7 +372,10 @@ extension RuntimeAssistedMutator.Action { } // Helper function to translate a range of inputs of this Action into FuzzIL variables. func translateInputs(_ r: PartialRangeFrom) throws -> [Variable] { - guard inputs.indices.upperBound >= r.lowerBound else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Missing inputs in range \(r) for operation \(operation)") } + guard inputs.indices.upperBound >= r.lowerBound else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Missing inputs in range \(r) for operation \(operation)") + } return try inputs[r].map({ try $0.translateToFuzzIL(withContext: context, using: b) }) } // Helper functions to translate actions to binary/unary operations or comparisons. diff --git a/Sources/Fuzzilli/Mutators/SpliceMutator.swift b/Sources/Fuzzilli/Mutators/SpliceMutator.swift index 1b264063b..8d19a6644 100644 --- a/Sources/Fuzzilli/Mutators/SpliceMutator.swift +++ b/Sources/Fuzzilli/Mutators/SpliceMutator.swift @@ -35,7 +35,8 @@ public class SpliceMutator: BaseInstructionMutator { // actually update that instruction to make spliced type definitions // available. if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) - || (instr.op is WasmBeginTypeGroup) { + || (instr.op is WasmBeginTypeGroup) + { return false } // It only makes sense to copy code if we're not currently in dead code. diff --git a/Sources/Fuzzilli/Profiles/DuktapeProfile.swift b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift index 0611eb8ed..b22ddef87 100644 --- a/Sources/Fuzzilli/Profiles/DuktapeProfile.swift +++ b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let duktapeProfile = Profile( processArgs: { randomize in ["--reprl"] @@ -27,10 +26,10 @@ let duktapeProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -52,13 +51,13 @@ let duktapeProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "CBOR.encode" : .function([.jsAnything] => .object()), - "CBOR.decode" : .function([.object()] => .object()), - "Duktape.fin" : .function([.object(), .opt(.function())] => .undefined), - "Duktape.act" : .function([.number] => .object()), - "Duktape.gc" : .function([] => .undefined), - "Duktape.compact" : .function([.object()] => .undefined), - "placeholder" : .function([] => .undefined), + "CBOR.encode": .function([.jsAnything] => .object()), + "CBOR.decode": .function([.object()] => .object()), + "Duktape.fin": .function([.object(), .opt(.function())] => .undefined), + "Duktape.act": .function([.number] => .object()), + "Duktape.gc": .function([] => .undefined), + "Duktape.compact": .function([.object()] => .undefined), + "placeholder": .function([] => .undefined), ], diff --git a/Sources/Fuzzilli/Profiles/JSCProfile.swift b/Sources/Fuzzilli/Profiles/JSCProfile.swift index 214a2f9d2..85b906036 100644 --- a/Sources/Fuzzilli/Profiles/JSCProfile.swift +++ b/Sources/Fuzzilli/Profiles/JSCProfile.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let ForceDFGCompilationGenerator = CodeGenerator("ForceDFGCompilationGenerator", inputs: .required(.function())) { b, f in +private let ForceDFGCompilationGenerator = CodeGenerator( + "ForceDFGCompilationGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -22,7 +23,9 @@ fileprivate let ForceDFGCompilationGenerator = CodeGenerator("ForceDFGCompilatio } } -fileprivate let ForceFTLCompilationGenerator = CodeGenerator("ForceFTLCompilationGenerator", inputs: .required(.function())) { b, f in +private let ForceFTLCompilationGenerator = CodeGenerator( + "ForceFTLCompilationGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -31,7 +34,7 @@ fileprivate let ForceFTLCompilationGenerator = CodeGenerator("ForceFTLCompilatio } } -fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in +private let GcGenerator = CodeGenerator("GcGenerator") { b in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) } @@ -49,7 +52,8 @@ let jscProfile = Profile( "--thresholdForFTLOptimizeSoon=1000", // Enable bounds check elimination validation "--validateBCE=true", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -70,18 +74,18 @@ let jscProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -100,7 +104,7 @@ let jscProfile = Profile( additionalCodeGenerators: [ (ForceDFGCompilationGenerator, 5), (ForceFTLCompilationGenerator, 5), - (GcGenerator, 5), + (GcGenerator, 5), ], additionalProgramTemplates: WeightedList([]), @@ -110,20 +114,20 @@ let jscProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "transferArrayBuffer" : .function([.object(ofGroup: "ArrayBuffer")] => .undefined), - "noInline" : .function([.function()] => .undefined), - "noFTL" : .function([.function()] => .undefined), - "createGlobalObject" : .function([] => .object()), - "OSRExit" : .function([] => .jsAnything), - "drainMicrotasks" : .function([] => .jsAnything), - "runString" : .function([.string] => .jsAnything), - "makeMasquerader" : .function([] => .jsAnything), - "fullGC" : .function([] => .undefined), - "edenGC" : .function([] => .undefined), - "fiatInt52" : .function([.number] => .number), - "forceGCSlowPaths" : .function([] => .jsAnything), - "ensureArrayStorage" : .function([] => .jsAnything), + "gc": .function([] => .undefined), + "transferArrayBuffer": .function([.object(ofGroup: "ArrayBuffer")] => .undefined), + "noInline": .function([.function()] => .undefined), + "noFTL": .function([.function()] => .undefined), + "createGlobalObject": .function([] => .object()), + "OSRExit": .function([] => .jsAnything), + "drainMicrotasks": .function([] => .jsAnything), + "runString": .function([.string] => .jsAnything), + "makeMasquerader": .function([] => .jsAnything), + "fullGC": .function([] => .undefined), + "edenGC": .function([] => .undefined), + "fiatInt52": .function([.number] => .number), + "forceGCSlowPaths": .function([] => .jsAnything), + "ensureArrayStorage": .function([] => .jsAnything), ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift index 912aa5b97..65f160296 100644 --- a/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift +++ b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let jerryscriptProfile = Profile( processArgs: { randomize in ["--reprl-fuzzilli"] @@ -20,17 +19,17 @@ let jerryscriptProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -52,10 +51,10 @@ let jerryscriptProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "print" : .function([] => .undefined), - "resourceName" : .function([] => .undefined), - "placeholder" : .function([] => .undefined), + "gc": .function([] => .undefined), + "print": .function([] => .undefined), + "resourceName": .function([] => .undefined), + "placeholder": .function([] => .undefined), ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/NjsProfile.swift b/Sources/Fuzzilli/Profiles/NjsProfile.swift index 6dc3408c1..42b01cd29 100644 --- a/Sources/Fuzzilli/Profiles/NjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/NjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let njsProfile = Profile( processArgs: { randomize in ["fuzz"] @@ -27,10 +26,10 @@ let njsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, diff --git a/Sources/Fuzzilli/Profiles/Profile.swift b/Sources/Fuzzilli/Profiles/Profile.swift index aca59b0e7..b8d0fc063 100644 --- a/Sources/Fuzzilli/Profiles/Profile.swift +++ b/Sources/Fuzzilli/Profiles/Profile.swift @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. - public struct Profile { public let processArgs: (_ randomize: Bool) -> [String] // if not nil, then this is profile for differential fuzzing public let processArgsReference: [String]? - public let processEnv: [String : String] + public let processEnv: [String: String] public let maxExecsBeforeRespawn: Int // Timeout either by value or interval in milliseconds. public let timeout: Timeout diff --git a/Sources/Fuzzilli/Profiles/QjsProfile.swift b/Sources/Fuzzilli/Profiles/QjsProfile.swift index a5e3e8b62..5a344b4f5 100644 --- a/Sources/Fuzzilli/Profiles/QjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let qjsProfile = Profile( processArgs: { randomize in ["--reprl"] @@ -27,10 +26,10 @@ let qjsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -53,7 +52,7 @@ let qjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "placeholder" : .function([] => .undefined) + "placeholder": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/QtjsProfile.swift b/Sources/Fuzzilli/Profiles/QtjsProfile.swift index 5c743062a..fddd2a071 100644 --- a/Sources/Fuzzilli/Profiles/QtjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QtjsProfile.swift @@ -13,10 +13,12 @@ // limitations under the License. // QV4 is the Execution Engine behind QTJS -fileprivate let ForceQV4JITGenerator = CodeGenerator("ForceQV4JITGenerator", inputs: .required(.function())) { b, f in +private let ForceQV4JITGenerator = CodeGenerator( + "ForceQV4JITGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) - b.buildRepeatLoop(n: 100){ _ in + b.buildRepeatLoop(n: 100) { _ in b.callFunction(f, withArgs: arguments) } } @@ -28,17 +30,17 @@ let qtjsProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -51,7 +53,7 @@ let qtjsProfile = Profile( ], additionalCodeGenerators: [ - (ForceQV4JITGenerator, 20), + (ForceQV4JITGenerator, 20) ], additionalProgramTemplates: WeightedList([]), @@ -61,7 +63,7 @@ let qtjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), + "gc": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/Serenity.swift b/Sources/Fuzzilli/Profiles/Serenity.swift index 12fbd404f..134cb875a 100644 --- a/Sources/Fuzzilli/Profiles/Serenity.swift +++ b/Sources/Fuzzilli/Profiles/Serenity.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let serenityProfile = Profile( processArgs: { randomize in return [""] }, processArgsReference: nil, @@ -23,12 +22,12 @@ let serenityProfile = Profile( maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - function main() { - """, - codeSuffix: """ - } - main(); - """, + function main() { + """, + codeSuffix: """ + } + main(); + """, ecmaVersion: ECMAScriptVersion.es6, startupTests: [ diff --git a/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift index bd857368d..4e4a1110b 100644 --- a/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift +++ b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let ForceSpidermonkeyIonGenerator = CodeGenerator("ForceSpidermonkeyIonGenerator", inputs: .required(.function())) { b, f in +private let ForceSpidermonkeyIonGenerator = CodeGenerator( + "ForceSpidermonkeyIonGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -22,7 +23,7 @@ fileprivate let ForceSpidermonkeyIonGenerator = CodeGenerator("ForceSpidermonkey } } -fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in +private let GcGenerator = CodeGenerator("GcGenerator") { b in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) } @@ -35,7 +36,8 @@ let spidermonkeyProfile = Profile( "--ion-extra-checks", "--fuzzing-safe", "--disable-oom-functions", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -60,12 +62,15 @@ let spidermonkeyProfile = Profile( args.append("--ion-licm=\(probability(0.9) ? "on": "off")") args.append("--ion-instruction-reordering=\(probability(0.9) ? "on": "off")") args.append("--cache-ir-stubs=\(probability(0.9) ? "on": "off")") - args.append(chooseUniform(from: ["--no-sse3", "--no-ssse3", "--no-sse41", "--no-sse42", "--enable-avx"])) + args.append( + chooseUniform(from: [ + "--no-sse3", "--no-ssse3", "--no-sse41", "--no-sse42", "--enable-avx", + ])) if probability(0.1) { args.append("--ion-regalloc=testbed") } args.append(probability(0.9) ? "--enable-watchtower" : "--disable-watchtower") - args.append("--ion-sink=\(probability(0.0) ? "on": "off")") // disabled + args.append("--ion-sink=\(probability(0.0) ? "on": "off")") // disabled return args }, @@ -78,11 +83,11 @@ let spidermonkeyProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -100,7 +105,7 @@ let spidermonkeyProfile = Profile( additionalCodeGenerators: [ (ForceSpidermonkeyIonGenerator, 10), - (GcGenerator, 10), + (GcGenerator, 10), ], additionalProgramTemplates: WeightedList([]), @@ -110,10 +115,10 @@ let spidermonkeyProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "enqueueJob" : .function([.function()] => .undefined), - "drainJobQueue" : .function([] => .undefined), - "bailout" : .function([] => .undefined), + "gc": .function([] => .undefined), + "enqueueJob": .function([.function()] => .undefined), + "drainJobQueue": .function([] => .undefined), + "bailout": .function([] => .undefined), ], diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 6fb2fe379..59ec66b44 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -12,33 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. +extension ILType { + public static let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) -public extension ILType { - static let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) + public static let jsD8Test = ILType.object( + ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) - static let jsD8Test = ILType.object(ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) + public static let jsD8FastCAPI = ILType.object( + ofGroup: "D8FastCAPI", withProperties: [], + withMethods: ["throw_no_fallback", "add_32bit_int"]) - static let jsD8FastCAPI = ILType.object(ofGroup: "D8FastCAPI", withProperties: [], withMethods: ["throw_no_fallback", "add_32bit_int"]) + public static let jsD8FastCAPIConstructor = ILType.constructor([] => .jsD8FastCAPI) - static let jsD8FastCAPIConstructor = ILType.constructor([] => .jsD8FastCAPI) + public static let gcTypeEnum = ILType.enumeration( + ofName: "gcType", withValues: ["minor", "major"]) + public static let gcExecutionEnum = ILType.enumeration( + ofName: "gcExecution", withValues: ["async", "sync"]) - static let gcTypeEnum = ILType.enumeration(ofName: "gcType", withValues: ["minor", "major"]) - static let gcExecutionEnum = ILType.enumeration(ofName: "gcExecution", withValues: ["async", "sync"]) - - static let jsWorker = object(ofGroup: "Worker", withMethods: ["postMessage","getMessage", "terminate", "terminateAndWait"]) - static let jsWorkerConstructor = constructor([.jsAnything, .object()] => jsWorker) + public static let jsWorker = object( + ofGroup: "Worker", + withMethods: ["postMessage", "getMessage", "terminate", "terminateAndWait"]) + public static let jsWorkerConstructor = + constructor([.jsAnything, .object()] => jsWorker) + object(ofGroup: "WorkerConstructor", withProperties: ["prototype"]) } public let gcOptions = ObjectGroup( name: "GCOptions", - instanceType: .object(ofGroup: "GCOptions", withProperties: ["type", "execution"], withMethods: []), - properties: ["type": .gcTypeEnum, - "execution": .gcExecutionEnum], + instanceType: .object( + ofGroup: "GCOptions", withProperties: ["type", "execution"], withMethods: []), + properties: [ + "type": .gcTypeEnum, + "execution": .gcExecutionEnum, + ], methods: [:]) -public extension ObjectGroup { - static let jsWorkers = ObjectGroup( +extension ObjectGroup { + public static let jsWorkers = ObjectGroup( name: "Worker", instanceType: .jsWorker, properties: [:], @@ -46,25 +56,25 @@ public extension ObjectGroup { "postMessage": [.jsAnything] => .undefined, "getMessage": [] => .jsAnything, "terminate": [] => .undefined, - "terminateAndWait": [] => .undefined + "terminateAndWait": [] => .undefined, ] ) - static let jsWorkerPrototype = + public static let jsWorkerPrototype = ObjectGroup.createPrototypeObjectGroup(jsWorkers, constructor: .jsWorkerConstructor) - static let jsWorkerConstructors = ObjectGroup( - name: "WorkerConstructor", - constructorPath: "Worker", - instanceType: .jsWorkerConstructor, - properties: [ - "prototype" : jsWorkerPrototype.instanceType, - ], - methods: [:] - ) + public static let jsWorkerConstructors = ObjectGroup( + name: "WorkerConstructor", + constructorPath: "Worker", + instanceType: .jsWorkerConstructor, + properties: [ + "prototype": jsWorkerPrototype.instanceType + ], + methods: [:] + ) } -public let fastCallables : [(group: ILType, method: String)] = [ +public let fastCallables: [(group: ILType, method: String)] = [ (group: .jsD8FastCAPI, method: "throw_no_fallback"), (group: .jsD8FastCAPI, method: "add_32bit_int"), ] @@ -78,14 +88,17 @@ public let V8GcGenerator = CodeGenerator("GcGenerator") { b in // return of gc to .undefined | .jsPromise. One could either chain a .then // or create two wrapper functions that are differently typed such that // fuzzilli always knows what the type of the return value is. - b.callFunction(gc, withArgs: b.findOrGenerateArguments(forSignature: b.fuzzer.environment.type(ofBuiltin: "gc").signature!)) + b.callFunction( + gc, + withArgs: b.findOrGenerateArguments( + forSignature: b.fuzzer.environment.type(ofBuiltin: "gc").signature!)) } public let V8AllocationTimeoutGenerator = CodeGenerator("AllocationTimeoutGenerator") { b in // Repeated GCs are expensive, so only rarely use an interval. let interval = probability(0.1) ? Int64.random(in: 100...10000) : -1 - let timeout = Int64.random(in: 0...(Bool.random() ? 10 : 100)) // prefer small values - b.eval("%SetAllocationTimeout(%@, %@)", with: [b.loadInt(interval), b.loadInt(timeout)]); + let timeout = Int64.random(in: 0...(Bool.random() ? 10 : 100)) // prefer small values + b.eval("%SetAllocationTimeout(%@, %@)", with: [b.loadInt(interval), b.loadInt(timeout)]) } public let V8MajorGcGenerator = CodeGenerator("MajorGcGenerator") { b in @@ -94,7 +107,9 @@ public let V8MajorGcGenerator = CodeGenerator("MajorGcGenerator") { b in b.eval("%MajorGCForCompilerTesting()") } -public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITCompilationThroughLoopGenerator", inputs: .required(.function())) { b, f in +public let ForceJITCompilationThroughLoopGenerator = CodeGenerator( + "ForceJITCompilationThroughLoopGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -105,7 +120,9 @@ public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITComp // Choose argument lists for four function calls of the same function with // interesting optimization patterns. -func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Variable], [Variable], [Variable], [Variable]) { +func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ( + [Variable], [Variable], [Variable], [Variable] +) { var reusePool: [[Variable]] = [b.randomArguments(forCalling: f)] let reuseProbabilities = [1.0, 0.9, 0.9, 0.5] @@ -122,7 +139,9 @@ func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Varia return (argumentLists[0], argumentLists[1], argumentLists[2], argumentLists[3]) } -private func forceCompilationGenerator(_ generatorName: String, optimizeName: String) -> CodeGenerator { +private func forceCompilationGenerator(_ generatorName: String, optimizeName: String) + -> CodeGenerator +{ return CodeGenerator(generatorName, inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) @@ -131,12 +150,12 @@ private func forceCompilationGenerator(_ generatorName: String, optimizeName: St b.callFunction(f, withArgs: args1, guard: guardCalls) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]) b.callFunction(f, withArgs: args2, guard: guardCalls) b.callFunction(f, withArgs: args3, guard: guardCalls) - b.eval("%\(optimizeName)(%@)", with: [f]); + b.eval("%\(optimizeName)(%@)", with: [f]) b.callFunction(f, withArgs: args4, guard: guardCalls) } @@ -149,34 +168,37 @@ public let ForceMaglevCompilationGenerator = forceCompilationGenerator( "ForceMaglevCompilationGenerator", optimizeName: "OptimizeMaglevOnNextCall") // Create a loop and force OSR in one of the iterations. -public let ForceOsrGenerator = CodeGenerator("ForceOsrGenerator", [ - GeneratorStub( - "ForceOsrBeginGenerator", - inContext: .single(.javascript), - provides: [.javascript] - ) { b in - let numIterations = Int.random(in: 2...50) - let loopVar = b.emit(BeginRepeatLoop(iterations: numIterations)).innerOutput - let condition = b.compare( - loopVar, with: b.loadInt(Int64.random(in: 0..([ - (primitiveCodeGenerator, 2), - (createObjectGenerator, 1), - (objectMakerGenerator, 1), - (objectConstructorGenerator, 1), - (objectClassGenerator, 1), - - (propertyStoreGenerator, 10), - (propertyLoadGenerator, 10), - (propertyConfigureGenerator, 5), - (functionDefinitionGenerator, 2), - (functionCallGenerator, 3), - (constructorCallGenerator, 2), - (functionJitCallGenerator, 2) - ])) + b.fuzzer.setCodeGenerators( + WeightedList([ + (primitiveCodeGenerator, 2), + (createObjectGenerator, 1), + (objectMakerGenerator, 1), + (objectConstructorGenerator, 1), + (objectClassGenerator, 1), + + (propertyStoreGenerator, 10), + (propertyLoadGenerator, 10), + (propertyConfigureGenerator, 5), + (functionDefinitionGenerator, 2), + (functionCallGenerator, 3), + (constructorCallGenerator, 2), + (functionJitCallGenerator, 2), + ])) // ... run some of the CodeGenerators to create some initial objects ... b.buildPrefix() @@ -482,21 +525,21 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let twoByteSubjectString = "f\\uD83D\\uDCA9ba\\u2603" let replacementCandidates = [ - "'X'", - "'$1$2$3'", - "'$$$&$`$\\'$1'", - "() => 'X'", - "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", - "() => 42" + "'X'", + "'$1$2$3'", + "'$$$&$`$\\'$1'", + "() => 'X'", + "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", + "() => 42", ] let lastIndices = [ - "undefined", "-1", "0", - "1", "2", "3", - "4", "5", "6", - "7", "8", "9", - "50", "4294967296", "2147483647", - "2147483648", "NaN", "Not a Number" + "undefined", "-1", "0", + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", + "50", "4294967296", "2147483647", + "2147483648", "NaN", "Not a Number", ] let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -518,59 +561,74 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let resultVar = b.loadNull() - b.buildTryCatchFinally(tryBody: { - let symbol = b.createNamedVariable(forBuiltin: "Symbol") - withEqualProbability({ - let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("replace", of: symbol) - let replacement = withEqualProbability({ - b.loadString(b.randomString()) - }, { - b.loadString(chooseUniform(from: replacementCandidates)) - }) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("split", of: symbol) - let randomSplitLimit = withEqualProbability({ - "undefined" - }, { - "'not a number'" - }, { - String(b.randomInt()) - }) - let limit = b.loadString(randomSplitLimit) - let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(variable: resultVar, value: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) + b.buildTryCatchFinally( + tryBody: { + let symbol = b.createNamedVariable(forBuiltin: "Symbol") + withEqualProbability( + { + let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("match", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("replace", of: symbol) + let replacement = withEqualProbability( + { + b.loadString(b.randomString()) + }, + { + b.loadString(chooseUniform(from: replacementCandidates)) + }) + let res = b.callComputedMethod( + prop, on: regExpVar, withArgs: [subjectVar, replacement]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("search", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("split", of: symbol) + let randomSplitLimit = withEqualProbability( + { + "undefined" + }, + { + "'not a number'" + }, + { + String(b.randomInt()) + }) + let limit = b.loadString(randomSplitLimit) + let res = b.callComputedMethod( + symbol, on: regExpVar, withArgs: [subjectVar, limit]) + b.reassign(variable: resultVar, value: res) + }, + { + let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }) + }, + catchBody: { _ in }) - }, catchBody: { _ in - }) b.build(n: 7) b.doReturn(resultVar) } - b.eval("%SetForceSlowPath(false)"); + b.eval("%SetForceSlowPath(false)") // compile the regexp once b.callFunction(f) let resFast = b.callFunction(f) - b.eval("%SetForceSlowPath(true)"); + b.eval("%SetForceSlowPath(true)") let resSlow = b.callFunction(f) - b.eval("%SetForceSlowPath(false)"); + b.eval("%SetForceSlowPath(false)") b.build(n: 15) } @@ -595,7 +653,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in } // Mark the function for deoptimization. Due to the recursive pattern above, on the outer // stack frames this should trigger a lazy deoptimization. - b.eval("%DeoptimizeNow();"); + b.eval("%DeoptimizeNow();") b.build(n: 30) b.doReturn(b.randomJsVariable()) } @@ -604,9 +662,9 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in b.reassign(variable: dummyFct, value: realFct) let args = b.randomArguments(forCalling: realFct) let guardCalls = probability(0.5) - b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]) b.callFunction(realFct, withArgs: args, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]); + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]) // Call the function. b.callFunction(realFct, withArgs: args, guard: guardCalls) } @@ -620,12 +678,13 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in // after the other. let mainSignatureBase = b.randomWasmSignature() let useTable64 = Bool.random() - let mainSignature = [useTable64 ? .wasmi64 : .wasmi32] + mainSignatureBase.parameterTypes + let mainSignature = + [useTable64 ? .wasmi64 : .wasmi32] + mainSignatureBase.parameterTypes => mainSignatureBase.outputTypes let numCallees = Int.random(in: 2...5) // Emit a TypeGroup to increase the chance for interesting wasm-gc cases. - b.wasmDefineTypeGroup() { + b.wasmDefineTypeGroup { b.build(n: 10) } @@ -642,14 +701,18 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in let table = wasmModule.addTable( elementType: .wasmFuncRef(), minSize: numCallees, - definedEntries: (0.. .integer, - "add_32bit_int": [.integer, .integer] => .integer +public let jsD8FastCAPI = ObjectGroup( + name: "D8FastCAPI", instanceType: .jsD8FastCAPI, properties: [:], + methods: [ + "throw_no_fallback": [] => .integer, + "add_32bit_int": [.integer, .integer] => .integer, ]) public let WasmFastCallFuzzer = WasmProgramTemplate("WasmFastCallFuzzer") { b in @@ -723,14 +791,19 @@ public let WasmFastCallFuzzer = WasmProgramTemplate("WasmFastCallFuzzer") { b in let wrappedSig = [.plain(b.type(of: apiObj))] + functionSig.parameters => functionSig.outputType let m = b.buildWasmModule { m in - let allWasmTypes: WeightedList = WeightedList([(.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), (.wasmFuncRef(), 1)]) - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(wrappedSig, availableTypes: allWasmTypes) - m.addWasmFunction(with: wasmSignature) {fbuilder, _, _ in + let allWasmTypes: WeightedList = WeightedList([ + (.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), + (.wasmFuncRef(), 1), + ]) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + wrappedSig, availableTypes: allWasmTypes) + m.addWasmFunction(with: wasmSignature) { fbuilder, _, _ in let args = b.randomWasmArguments(forWasmSignature: wasmSignature) if let args { - let maybeRet = fbuilder.wasmJsCall(function: wrapped, withArgs: args, withWasmSignature: wasmSignature) + let maybeRet = fbuilder.wasmJsCall( + function: wrapped, withArgs: args, withWasmSignature: wasmSignature) if let ret = maybeRet { - return [ret] + return [ret] } } else { Logger(withLabel: "V8CommonProfile").error("Arguments should have been generated") @@ -758,8 +831,11 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in b.build(n: 10) let target = fastCallables.randomElement()! let apiObj = b.findOrGenerateType(target.group) - let functionSig = chooseUniform(from: b.methodSignatures(of: target.method, on: target.group)) - let apiCall = b.callMethod(target.method, on: apiObj, withArgs: b.findOrGenerateArguments(forSignature: functionSig), guard: true) + let functionSig = chooseUniform( + from: b.methodSignatures(of: target.method, on: target.group)) + let apiCall = b.callMethod( + target.method, on: apiObj, + withArgs: b.findOrGenerateArguments(forSignature: functionSig), guard: true) b.doReturn(apiCall) } @@ -767,12 +843,12 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in let guardCalls = probability(0.5) b.callFunction(f, withArgs: args, guard: guardCalls) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]) b.callFunction(f, withArgs: args, guard: guardCalls) b.callFunction(f, withArgs: args, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]) b.callFunction(f, withArgs: args, guard: guardCalls) @@ -785,19 +861,21 @@ public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") let containingFct = b.buildPlainFunction(with: b.randomParameters()) { args in // The function to install the prototypes on. let params = b.randomParameters() - let body = {(args: [Variable]) in + let body = { (args: [Variable]) in b.build(n: 20) b.doReturn(b.randomVariable(forUseAs: .object())) } let fct = withEqualProbability( - {b.buildPlainFunction(with: params, body)}, - {b.buildArrowFunction(with: params, body)}, - {b.buildGeneratorFunction(with: params, body)}, // not a valid constructor - {b.buildAsyncFunction(with: params, body)}, // not a valid constructor - {b.buildConstructor(with: params, body)}, - {b.buildClassDefinition(withSuperclass: b.randomVariable(forUseAs: .object())) { _ in - b.build(n: 30) - }} + { b.buildPlainFunction(with: params, body) }, + { b.buildArrowFunction(with: params, body) }, + { b.buildGeneratorFunction(with: params, body) }, // not a valid constructor + { b.buildAsyncFunction(with: params, body) }, // not a valid constructor + { b.buildConstructor(with: params, body) }, + { + b.buildClassDefinition(withSuperclass: b.randomVariable(forUseAs: .object())) { _ in + b.build(n: 30) + } + } ) // Explicitly expose the prototype property to make modifications of it more likely. b.getProperty("prototype", of: fct) @@ -827,34 +905,36 @@ public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") public let TurbofanTierUpNonInlinedCallFuzzer = ProgramTemplate("TurbofanTierUpNonInlinedCallFuzzer") { b in - b.buildPrefix() - b.build(n: 50) - // Find a function (or generate a new one) to be marked as "never optimize". - let unoptimizedFunction = b.randomVariable(ofType: .function()) - ?? b.buildPlainFunction(with: .parameters(n: 2)) { _ in - b.build(n: 20) - b.doReturn(b.randomJsVariable()) + b.buildPrefix() + b.build(n: 50) + // Find a function (or generate a new one) to be marked as "never optimize". + let unoptimizedFunction = + b.randomVariable(ofType: .function()) + ?? b.buildPlainFunction(with: .parameters(n: 2)) { _ in + b.build(n: 20) + b.doReturn(b.randomJsVariable()) + } + b.eval("%NeverOptimizeFunction(%@)", with: [unoptimizedFunction]) + // Create another function that calls the unoptimized function. This will always create a real + // call instead of inlining it. + let optimizedFunction = b.buildPlainFunction(with: .parameters(n: 0)) { _ in + // This should be able to generate interesting things including calls to the unoptimized + // function in all kinds of control flow. + b.build(n: 30) + // Also explicitly emit a call to the unoptimized function. + b.callFunction( + unoptimizedFunction, withArgs: b.randomArguments(forCalling: unoptimizedFunction)) + b.build(n: 10) } - b.eval("%NeverOptimizeFunction(%@)", with: [unoptimizedFunction]) - // Create another function that calls the unoptimized function. This will always create a real - // call instead of inlining it. - let optimizedFunction = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - // This should be able to generate interesting things including calls to the unoptimized - // function in all kinds of control flow. - b.build(n: 30) - // Also explicitly emit a call to the unoptimized function. - b.callFunction(unoptimizedFunction, withArgs: b.randomArguments(forCalling: unoptimizedFunction)) - b.build(n: 10) + // Collect feedback and optimize the function. + // Guard all calls. The path where they throw is still interesting as there are + // optimizations that affect the unwinding logic which we'd like to get coverage for as well. + b.eval("%PrepareFunctionForOptimization(%@)", with: [optimizedFunction]) + b.callFunction(optimizedFunction, guard: true) + b.callFunction(optimizedFunction, guard: true) + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [optimizedFunction]) + b.callFunction(optimizedFunction, guard: true) } - // Collect feedback and optimize the function. - // Guard all calls. The path where they throw is still interesting as there are - // optimizations that affect the unwinding logic which we'd like to get coverage for as well. - b.eval("%PrepareFunctionForOptimization(%@)", with: [optimizedFunction]); - b.callFunction(optimizedFunction, guard: true) - b.callFunction(optimizedFunction, guard: true) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [optimizedFunction]); - b.callFunction(optimizedFunction, guard: true) -} // Configure V8 invocation arguments. `forSandbox` is used by the V8SandboxProfile. As the sandbox // fuzzer does not crash on regular assertions, most validation flags do not make sense in that @@ -873,7 +953,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { "--wasm-staging", "--wasm-fast-api", "--expose-fast-api", - "--wasm-test-streaming", // WebAssembly.compileStreaming & WebAssembly.instantiateStreaming() + "--wasm-test-streaming", // WebAssembly.compileStreaming & WebAssembly.instantiateStreaming() ] if forSandbox { args.append("--sandbox-fuzzing") @@ -892,9 +972,10 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--maglev-as-top-tier") } } else if probability(0.1) { - args.append(probability(0.5) - ? "--turbo-instruction-scheduling" - : "--turbo-stress-instruction-scheduling") + args.append( + probability(0.5) + ? "--turbo-instruction-scheduling" + : "--turbo-stress-instruction-scheduling") } if probability(0.1) { @@ -963,7 +1044,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } if probability(0.2) { args.append("--maglev-non-eager-inlining") - if probability(0.4) { // TODO: @tacet decrease this probability to max 0.2 + if probability(0.4) { // TODO: @tacet decrease this probability to max 0.2 args.append("--max-maglev-inlined-bytecode-size-small=0") } } @@ -977,7 +1058,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--turbolev") if probability(0.82) { args.append("--turbolev-future") - if probability(0.3) { // TODO: @tacet change to 0.15 + if probability(0.3) { // TODO: @tacet change to 0.15 args.append("--max-inlined-bytecode-size-small=0") } } @@ -1021,14 +1102,14 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { // Temporarily enable the three flags below with high probability to // stress-test JSPI. // Lower the probabilities once we have enough coverage. - if (probability(0.5)) { + if probability(0.5) { let stackSwitchingSize = Int.random(in: 1...300) args.append("--wasm-stack-switching-stack-size=\(stackSwitchingSize)") } - if (probability(0.5)) { + if probability(0.5) { args.append("--experimental-wasm-growable-stacks") } - if (probability(0.5)) { + if probability(0.5) { args.append("--stress-wasm-stack-switching") } @@ -1060,7 +1141,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--assert-types") } if (!args.contains("--no-maglev") || args.contains("--turbolev")) && probability(0.1) { - // TODO(tacet): update the Turbolev conditions to !args.contains("--no-turbolev") after Turbolev trial + // TODO(tacet): update the Turbolev conditions to !args.contains("--no-turbolev") after Turbolev trial args.append("--maglev-assert-types") } if probability(0.1) { @@ -1078,7 +1159,9 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } if probability(0.1) { - args.append("--deopt-every-n-times=\(chooseUniform(from: [100, 250, 500, 1000, 2500, 5000, 10000]))") + args.append( + "--deopt-every-n-times=\(chooseUniform(from: [100, 250, 500, 1000, 2500, 5000, 10000]))" + ) } if probability(0.1) { args.append("--stress-ic") @@ -1109,17 +1192,21 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--stress-wasm-memory-moving") } if probability(0.4) { - args.append(chooseUniform( - from: ["--gc-interval=\(Int.random(in: 100...10000))", - "--random-gc-interval=\(Int.random(in: 1000...10000))"])) + args.append( + chooseUniform( + from: [ + "--gc-interval=\(Int.random(in: 100...10000))", + "--random-gc-interval=\(Int.random(in: 1000...10000))", + ])) } if probability(0.4) { args.append("--concurrent-recompilation-queue-length=\(Int.random(in: 4...64))") args.append("--concurrent-recompilation-delay=\(Int.random(in: 1...500))") } if probability(0.6) { - args.append(chooseUniform( - from: ["--stress-compaction", "--stress-compaction-random"])) + args.append( + chooseUniform( + from: ["--stress-compaction", "--stress-compaction-random"])) } } @@ -1160,7 +1247,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { // Compiler related flags chooseBooleanFlag("turbo-move-optimization") - chooseBooleanFlag("turbo-jt") // jump threading + chooseBooleanFlag("turbo-jt") // jump threading chooseBooleanFlag("turbo-loop-peeling") chooseBooleanFlag("turbo-loop-variable") chooseBooleanFlag("turbo-loop-rotation") @@ -1175,7 +1262,11 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { chooseBooleanFlag("turbo-load-elimination") chooseBooleanFlag("turbo-inlining") chooseBooleanFlag("turbo-splitting") - args.append(chooseUniform(from: ["--no-enable-sse3", "--no-enable-ssse3", "--no-enable-sse4-1", "--no-enable-sse4-2", "--no-enable-avx", "--no-enable-avx2"])) + args.append( + chooseUniform(from: [ + "--no-enable-sse3", "--no-enable-ssse3", "--no-enable-sse4-1", "--no-enable-sse4-2", + "--no-enable-avx", "--no-enable-avx2", + ])) chooseBooleanFlag("turboshaft-loop-unrolling") chooseBooleanFlag("turboshaft-load-elimination") diff --git a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift index 2f8aa988b..8c404a79f 100644 --- a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let v8DumplingProfile = Profile( processArgs: { randomize in var args = [ @@ -55,7 +54,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--predictable" + "--predictable", ], processEnv: [:], @@ -65,56 +64,56 @@ let v8DumplingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - // --- Determinism Shim --- - (function() { - const originalDate = Date; - const FIXED_TIME = 1767225600000; - const FIXED_STRING = new originalDate(FIXED_TIME).toString(); - - Date.now = function() { return FIXED_TIME; }; - globalThis.Date = new Proxy(originalDate, { - construct(target, args) { - if (args.length === 0) return new target(FIXED_TIME); - return new target(...args); - }, - apply(target, thisArg, args) { return FIXED_STRING; } - }); - globalThis.Date.prototype = originalDate.prototype; - - // Math.random shim - const rng = function() { - let s = 0x12345678; - return function() { - s ^= s << 13; s ^= s >> 17; s ^= s << 5; - return (s >>> 0) / 4294967296; - }; - }(); - Math.random = rng; - - if (typeof Temporal !== 'undefined' && Temporal.Now) { - const fixedInstant = Temporal.Instant.fromEpochMilliseconds(FIXED_TIME); - - Temporal.Now.instant = () => fixedInstant; - - // Shim Zoned/Plain methods to use the fixed instant - Temporal.Now.zonedDateTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()); - - Temporal.Now.plainDateTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDateTime(); - - Temporal.Now.plainDateISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDate(); - - Temporal.Now.plainTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainTime(); - } - })(); - // --- End Determinism Shim --- - """, + // --- Determinism Shim --- + (function() { + const originalDate = Date; + const FIXED_TIME = 1767225600000; + const FIXED_STRING = new originalDate(FIXED_TIME).toString(); + + Date.now = function() { return FIXED_TIME; }; + globalThis.Date = new Proxy(originalDate, { + construct(target, args) { + if (args.length === 0) return new target(FIXED_TIME); + return new target(...args); + }, + apply(target, thisArg, args) { return FIXED_STRING; } + }); + globalThis.Date.prototype = originalDate.prototype; + + // Math.random shim + const rng = function() { + let s = 0x12345678; + return function() { + s ^= s << 13; s ^= s >> 17; s ^= s << 5; + return (s >>> 0) / 4294967296; + }; + }(); + Math.random = rng; + + if (typeof Temporal !== 'undefined' && Temporal.Now) { + const fixedInstant = Temporal.Instant.fromEpochMilliseconds(FIXED_TIME); + + Temporal.Now.instant = () => fixedInstant; + + // Shim Zoned/Plain methods to use the fixed instant + Temporal.Now.zonedDateTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()); + + Temporal.Now.plainDateTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDateTime(); + + Temporal.Now.plainDateISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDate(); + + Temporal.Now.plainTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainTime(); + } + })(); + // --- End Determinism Shim --- + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -123,21 +122,21 @@ let v8DumplingProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), - (V8GcGenerator, 10), + (V8GcGenerator, 10), ], additionalProgramTemplates: WeightedList([ - (MapTransitionFuzzer, 1), - (ValueSerializerFuzzer, 1), - (V8RegExpFuzzer, 1), - (FastApiCallFuzzer, 1), - (LazyDeoptFuzzer, 1), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), ]), disabledCodeGenerators: [], @@ -145,9 +144,10 @@ let v8DumplingProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .jsD8, - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .jsD8, + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], diff --git a/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift index 6bcafe668..a3985adbb 100644 --- a/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. - // This value generator inserts Hole leaks into the program. Use this if you // want to fuzz for Memory Corruption using holes, this should be used in // conjunction with the --hole-fuzzing runtime flag. -fileprivate let HoleLeakGenerator = CodeGenerator("HoleLeakGenerator", produces: [.jsAnything]) { b in +private let HoleLeakGenerator = CodeGenerator("HoleLeakGenerator", produces: [.jsAnything]) { b in b.eval("%LeakHole()", hasOutput: true) } @@ -44,10 +43,10 @@ let v8HoleFuzzingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -68,25 +67,25 @@ let v8HoleFuzzingProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (V8GcGenerator, 10), - (HoleLeakGenerator, 25), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (V8GcGenerator, 10), + (HoleLeakGenerator, 25), ], - additionalProgramTemplates: WeightedList([ - ]), + additionalProgramTemplates: WeightedList([]), disabledCodeGenerators: [], disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .object(), - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .object(), + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], diff --git a/Sources/Fuzzilli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift index 6d1960729..3ffb35672 100644 --- a/Sources/Fuzzilli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - public let v8Profile = Profile( - processArgs: {randomize in - v8ProcessArgs(randomize: randomize, forSandbox: false) + processArgs: { randomize in + v8ProcessArgs(randomize: randomize, forSandbox: false) }, processArgsReference: nil, @@ -28,10 +27,10 @@ public let v8Profile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -57,37 +56,37 @@ public let v8Profile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), - - (WorkerGenerator, 10), - (V8GcGenerator, 5), - (V8AllocationTimeoutGenerator, 5), - (V8MajorGcGenerator, 5), - - (WasmStructGenerator, 15), - (WasmArrayGenerator, 15), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 5), - (HoleNanGenerator, 5), - (UndefinedNanGenerator, 5), - (StringShapeGenerator, 5), - (HeapNumberGenerator, 5), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), + + (WorkerGenerator, 10), + (V8GcGenerator, 5), + (V8AllocationTimeoutGenerator, 5), + (V8MajorGcGenerator, 5), + + (WasmStructGenerator, 15), + (WasmArrayGenerator, 15), + (SharedObjectGenerator, 5), + (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), + (HeapNumberGenerator, 5), ], additionalProgramTemplates: WeightedList([ - (MapTransitionFuzzer, 1), - (ValueSerializerFuzzer, 1), - (V8RegExpFuzzer, 1), - (WasmFastCallFuzzer, 1), - (FastApiCallFuzzer, 1), - (LazyDeoptFuzzer, 1), - (WasmDeoptFuzzer, 1), - (WasmTurbofanFuzzer, 1), - (ProtoAssignSeqOptFuzzer, 1), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (WasmFastCallFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), + (WasmDeoptFuzzer, 1), + (WasmTurbofanFuzzer, 1), + (ProtoAssignSeqOptFuzzer, 1), (TurbofanTierUpNonInlinedCallFuzzer, 1), ]), @@ -96,8 +95,8 @@ public let v8Profile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .jsD8, + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .jsD8, "Worker": .jsWorkerConstructor, // via --expose-externalize-string: "externalizeString": .function([.plain(.jsString)] => .jsString), @@ -106,7 +105,10 @@ public let v8Profile = Profile( "createExternalizableTwoByteString": .function([.plain(.jsString)] => .jsString), ], - additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions, .jsWorkers, .jsWorkerPrototype, .jsWorkerConstructors], + additionalObjectGroups: [ + jsD8, jsD8Test, jsD8FastCAPI, gcOptions, .jsWorkers, .jsWorkerPrototype, + .jsWorkerConstructors, + ], additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], diff --git a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift index 38744e23b..7f4c4f0ef 100644 --- a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. - // A post-processor that inserts calls to the sandbox corruption functions (defined in the codeSuffix below) into the generated samples. -fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { +private struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { func process(_ program: Program, for fuzzer: Fuzzer) throws -> Program { // We don't instrument every generated program since we still want the fuzzer to make progress towards // discovering more interestesting programs and adding them to the corpus. Corrupting objects in every @@ -31,9 +30,11 @@ fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { func corruptSomething() { // TODO: Currently, Fuzzilli wraps sandbox corruptions inside `b.eval(...)`. Because Fuzzilli treats `eval` strings as opaque, the mutation engine cannot genetically evolve the `pathArray` tuples or seeds. Implementing native Instruction classes (e.g. `.corruptDataWithBitflip(...)`) would allow Fuzzilli to structurally mutate these corruption paths. // Make sure that we get a JS variable that is not a primitive. - guard let target = b.findVariable(satisfying: { v in - !b.type(of: v).Is(.primitive) && b.type(of: v).Is(.jsAnything) - }) else { return } + guard + let target = b.findVariable(satisfying: { v in + !b.type(of: v).Is(.primitive) && b.type(of: v).Is(.jsAnything) + }) + else { return } let numCorruptions = Int.random(in: 1...3) for _ in 0..> 1 - let randomMagnitudeValue = lower == upper ? lower : UInt64.random(in: lower.. 1s), which may cause crashing samples to time out before the stack trace has been captured (in which case Fuzzilli will discard the sample) // - redzone=128: This value is used by Clusterfuzz for reproducing testcases so we should use the same value - processEnv: ["ASAN_OPTIONS" : "abort_on_error=1:handle_sigill=1:symbolize=false:redzone=128", "UBSAN_OPTIONS" : "abort_on_error=1:symbolize=false:redzone=128"], + processEnv: [ + "ASAN_OPTIONS": "abort_on_error=1:handle_sigill=1:symbolize=false:redzone=128", + "UBSAN_OPTIONS": "abort_on_error=1:symbolize=false:redzone=128", + ], maxExecsBeforeRespawn: 1000, @@ -168,336 +175,336 @@ let v8SandboxProfile = Profile( timeout: Timeout.interval(500, 1200), codePrefix: """ - // - // BEGIN FUZZER GENERATED CODE - // + // + // BEGIN FUZZER GENERATED CODE + // - """, + """, codeSuffix: """ - // - // BEGIN FUZZER HELPER CODE - // - - // The following functions corrupt a given object in a deterministic fashion (based on the provided seed and path) and log the steps being performed. + // + // BEGIN FUZZER HELPER CODE + // - function getSandboxCorruptionHelpers() { - // In general, memory contents are represented as (unsigned) BigInts, everything else (addresses, offsets, etc.) are Numbers. + // The following functions corrupt a given object in a deterministic fashion (based on the provided seed and path) and log the steps being performed. - function assert(c) { - if (!c) { - throw new Error("Assertion in the in-sandbox-corruption API failed!"); - } - } + function getSandboxCorruptionHelpers() { + // In general, memory contents are represented as (unsigned) BigInts, everything else (addresses, offsets, etc.) are Numbers. - const kHeapObjectTag = 0x1n; - // V8 uses the two lowest bits as tag bits: 0x1 to indicate HeapObject vs Smi and 0x2 to indicate a weak reference. - const kHeapObjectTagMask = 0x3n; - // Offsets should be a multiple of 4, as that's the typical field size. - const kOffsetAlignmentMask = ~0x3; - - const builtins = Sandbox.getBuiltinNames(); - assert(builtins.length > 0); - - const Step = { - NEIGHBOR: 0, - POINTER: 1, - }; - - // Helper class for accessing in-sandbox memory. - class Memory { - constructor() { - let buffer = new Sandbox.MemoryView(0, 0x100000000); - this.dataView = new DataView(buffer); - this.taggedView = new Uint32Array(buffer); - } - - read(addr, numBits) { - switch (numBits) { - case 8: return BigInt(this.dataView.getUint8(addr)); - case 16: return BigInt(this.dataView.getUint16(addr, true)); - case 32: return BigInt(this.dataView.getUint32(addr, true)); - } - } + function assert(c) { + if (!c) { + throw new Error("Assertion in the in-sandbox-corruption API failed!"); + } + } - write(addr, value, numBits) { - switch (numBits) { - case 8: this.dataView.setUint8(addr, Number(value)); break; - case 16: this.dataView.setUint16(addr, Number(value), true); break; - case 32: this.dataView.setUint32(addr, Number(value), true); break; - } - } + const kHeapObjectTag = 0x1n; + // V8 uses the two lowest bits as tag bits: 0x1 to indicate HeapObject vs Smi and 0x2 to indicate a weak reference. + const kHeapObjectTagMask = 0x3n; + // Offsets should be a multiple of 4, as that's the typical field size. + const kOffsetAlignmentMask = ~0x3; + + const builtins = Sandbox.getBuiltinNames(); + assert(builtins.length > 0); + + const Step = { + NEIGHBOR: 0, + POINTER: 1, + }; + + // Helper class for accessing in-sandbox memory. + class Memory { + constructor() { + let buffer = new Sandbox.MemoryView(0, 0x100000000); + this.dataView = new DataView(buffer); + this.taggedView = new Uint32Array(buffer); + } - copyTagged(source, destination, size) { - assert(size % 4 == 0); - let toIndex = destination / 4; - let startIndex = source / 4; - let endIndex = (source + size) / 4; - this.taggedView.copyWithin(toIndex, startIndex, endIndex); - } + read(addr, numBits) { + switch (numBits) { + case 8: return BigInt(this.dataView.getUint8(addr)); + case 16: return BigInt(this.dataView.getUint16(addr, true)); + case 32: return BigInt(this.dataView.getUint32(addr, true)); } - let memory = new Memory; - - // A worker thread that corrupts memory from the background. - // - // The main thread can post messages to this worker which contain - // effectively (address, valueA, valueB) triples. This worker - // will then permanently flip all the given addresses between - // valueA and valueB. This for example makes it possible to find - // double-fetch issues and similar bugs. - function workerFunc() { - let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); - let work = []; - let iteration = 0; - - onmessage = function(e) { - if (work.length == 0) { - // Time to start working. - setTimeout(doWork); - } - work.push(e.data); - } + } - function corrupt(address, value, size) { - switch (size) { - case 8: - memory.setUint8(address, value); - break; - case 16: - memory.setUint16(address, value, true); - break; - case 32: - memory.setUint32(address, value, true); - break; - } - } + write(addr, value, numBits) { + switch (numBits) { + case 8: this.dataView.setUint8(addr, Number(value)); break; + case 16: this.dataView.setUint16(addr, Number(value), true); break; + case 32: this.dataView.setUint32(addr, Number(value), true); break; + } + } - function doWork() { - iteration++; - for (let item of work) { - let value = (iteration % 2) == 0 ? item.valueA : item.valueB; - corrupt(item.address, value, item.size); - } - // Schedule the next round of work. - setTimeout(doWork); - } + copyTagged(source, destination, size) { + assert(size % 4 == 0); + let toIndex = destination / 4; + let startIndex = source / 4; + let endIndex = (source + size) / 4; + this.taggedView.copyWithin(toIndex, startIndex, endIndex); + } + } + let memory = new Memory; + + // A worker thread that corrupts memory from the background. + // + // The main thread can post messages to this worker which contain + // effectively (address, valueA, valueB) triples. This worker + // will then permanently flip all the given addresses between + // valueA and valueB. This for example makes it possible to find + // double-fetch issues and similar bugs. + function workerFunc() { + let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); + let work = []; + let iteration = 0; + + onmessage = function(e) { + if (work.length == 0) { + // Time to start working. + setTimeout(doWork); } - if (typeof globalThis.memory_corruption_worker === 'undefined') { - // Define as non-configurable and non-enumerable property. - let worker = new Worker(workerFunc, {type: 'function'}); - Object.defineProperty(globalThis, 'memory_corruption_worker', {value: worker}); + work.push(e.data); + } + + function corrupt(address, value, size) { + switch (size) { + case 8: + memory.setUint8(address, value); + break; + case 16: + memory.setUint16(address, value, true); + break; + case 32: + memory.setUint32(address, value, true); + break; } + } + function doWork() { + iteration++; + for (let item of work) { + let value = (iteration % 2) == 0 ? item.valueA : item.valueB; + corrupt(item.address, value, item.size); + } + // Schedule the next round of work. + setTimeout(doWork); + } + } + if (typeof globalThis.memory_corruption_worker === 'undefined') { + // Define as non-configurable and non-enumerable property. + let worker = new Worker(workerFunc, {type: 'function'}); + Object.defineProperty(globalThis, 'memory_corruption_worker', {value: worker}); + } - // Helper function to deterministically find a random neighbor object. - // - // This logic is designed to deal with a (somewhat) non-deterministic heap layout to ensure that test cases are reproducible. - // In practice, it should most of the time find the same neighbor object if (a) that object is always allocated after the - // start object, (b) is within the first N (currently 100) objects, and (c) is always the first neighbor of its instance type. - // - // This is achieved by iterating over the heap starting from the start object and computing a simple 16-bit hash value for each - // object. At the end, we select the first object whose hash is closest to a random 16-bit hash query. - // Note that we always take the first object if there are multiple objects with the same instance type. - // For finding later neighbors, we rely on the traversal path containing multiple Step.NEIGHBOR entries. - function findRandomNeighborObject(addr, hashQuery) { - const N = 100; - const kUint16Max = 0xffff; - const kUnknownInstanceId = kUint16Max; - - // Simple hash function for 16-bit unsigned integers. See https://github.com/skeeto/hash-prospector - function hash16(x) { - assert(x >= 0 && x <= kUint16Max); - x ^= x >> 8; - x = (x * 0x88B5) & 0xffff; - x ^= x >> 7; - x = (x * 0xdB2d) & 0xffff; - x ^= x >> 9; - return x; - } - hashQuery = hashQuery & 0xffff; - let currentWinner = addr; - let currentBest = kUint16Max; + // Helper function to deterministically find a random neighbor object. + // + // This logic is designed to deal with a (somewhat) non-deterministic heap layout to ensure that test cases are reproducible. + // In practice, it should most of the time find the same neighbor object if (a) that object is always allocated after the + // start object, (b) is within the first N (currently 100) objects, and (c) is always the first neighbor of its instance type. + // + // This is achieved by iterating over the heap starting from the start object and computing a simple 16-bit hash value for each + // object. At the end, we select the first object whose hash is closest to a random 16-bit hash query. + // Note that we always take the first object if there are multiple objects with the same instance type. + // For finding later neighbors, we rely on the traversal path containing multiple Step.NEIGHBOR entries. + function findRandomNeighborObject(addr, hashQuery) { + const N = 100; + const kUint16Max = 0xffff; + const kUnknownInstanceId = kUint16Max; + + // Simple hash function for 16-bit unsigned integers. See https://github.com/skeeto/hash-prospector + function hash16(x) { + assert(x >= 0 && x <= kUint16Max); + x ^= x >> 8; + x = (x * 0x88B5) & 0xffff; + x ^= x >> 7; + x = (x * 0xdB2d) & 0xffff; + x ^= x >> 9; + return x; + } - for (let i = 0; i < N; i++) { - addr += Sandbox.getSizeOfObjectAt(addr); - let typeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); - if (typeId == kUnknownInstanceId) { - break; - } - let hash = hash16(typeId); - let score = Math.abs(hash - hashQuery); - if (score < currentBest) { - currentBest = score; - currentWinner = addr; - } - } + hashQuery = hashQuery & 0xffff; + let currentWinner = addr; + let currentBest = kUint16Max; - return currentWinner; + for (let i = 0; i < N; i++) { + addr += Sandbox.getSizeOfObjectAt(addr); + let typeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); + if (typeId == kUnknownInstanceId) { + break; } - - // Helper function to create a copy of the object at the given address and return the address of the copy. - // This is for example useful when we would like to corrupt a read-only object: in that case, we can then instead - // create a copy of the read-only object, install that into whichever object references is, then corrupt the copy. - function copyObjectAt(source) { - let objectSize = Sandbox.getSizeOfObjectAt(source); - // Simple way to get a placeholder object that's large enough: create a sequential string. - // TODO(saelo): maybe add a method to the sandbox api to construct an object of the appropriate size. - let placeholder = Array(objectSize).fill("a").join(""); - let destination = Sandbox.getAddressOf(placeholder); - memory.copyTagged(source, destination, objectSize); - return destination; + let hash = hash16(typeId); + let score = Math.abs(hash - hashQuery); + if (score < currentBest) { + currentBest = score; + currentWinner = addr; } + } - function getRandomAlignedOffset(addr, offsetSeed) { - let objectSize = Sandbox.getSizeOfObjectAt(addr); - return (offsetSeed % objectSize) & kOffsetAlignmentMask; - } + return currentWinner; + } - function getBaseAddress(obj) { - try { - if (!Sandbox.isWritable(obj)) return null; - return Sandbox.getAddressOf(obj); - } catch (e) { - // Presumably, |obj| is a Smi, not a HeapObject. - return null; - } - } + // Helper function to create a copy of the object at the given address and return the address of the copy. + // This is for example useful when we would like to corrupt a read-only object: in that case, we can then instead + // create a copy of the read-only object, install that into whichever object references is, then corrupt the copy. + function copyObjectAt(source) { + let objectSize = Sandbox.getSizeOfObjectAt(source); + // Simple way to get a placeholder object that's large enough: create a sequential string. + // TODO(saelo): maybe add a method to the sandbox api to construct an object of the appropriate size. + let placeholder = Array(objectSize).fill("a").join(""); + let destination = Sandbox.getAddressOf(placeholder); + memory.copyTagged(source, destination, objectSize); + return destination; + } + + function getRandomAlignedOffset(addr, offsetSeed) { + let objectSize = Sandbox.getSizeOfObjectAt(addr); + return (offsetSeed % objectSize) & kOffsetAlignmentMask; + } - function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { - let baseAddr = getBaseAddress(obj); - if (!baseAddr) return null; + function getBaseAddress(obj) { + try { + if (!Sandbox.isWritable(obj)) return null; + return Sandbox.getAddressOf(obj); + } catch (e) { + // Presumably, |obj| is a Smi, not a HeapObject. + return null; + } + } - let addr = evaluateTraversalPath(baseAddr, path); - if (!addr) return null; + function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return null; - let offset = getRandomAlignedOffset(addr, offsetSeed); - offset += subFieldOffset; + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return null; - let oldValue = memory.read(addr + offset, numBitsToCorrupt); - return { addr, offset, oldValue, finalizeDataCorruption }; - } + let offset = getRandomAlignedOffset(addr, offsetSeed); + offset += subFieldOffset; + + let oldValue = memory.read(addr + offset, numBitsToCorrupt); + return { addr, offset, oldValue, finalizeDataCorruption }; + } - function finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, typeString) { - assert(oldValue >= 0 && oldValue < (1n << BigInt(numBitsToCorrupt))); - assert(newValue >= 0 && newValue < (1n << BigInt(numBitsToCorrupt))); + function finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, typeString) { + assert(oldValue >= 0 && oldValue < (1n << BigInt(numBitsToCorrupt))); + assert(newValue >= 0 && newValue < (1n << BigInt(numBitsToCorrupt))); - memory.write(addr + offset, newValue, numBitsToCorrupt); - print(" Corrupted " + numBitsToCorrupt + "-bit field (" + typeString + ") at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + memory.write(addr + offset, newValue, numBitsToCorrupt); + print(" Corrupted " + numBitsToCorrupt + "-bit field (" + typeString + ") at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + } + + // The path argument is an array of [Step, Value] tuples. + // If Step === Step.NEIGHBOR, Value is the exact 16-bit hash query. + // If Step === Step.POINTER, Value is a random UInt32 seed used to calculate an aligned offset. + function evaluateTraversalPath(addr, path) { + let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); + print("Corrupting memory starting from object at 0x" + addr.toString(16) + " of type " + instanceType); + + for (let [stepType, seedValue] of path) { + if (!Sandbox.isWritableObjectAt(addr)) { + print(" Not corrupting read-only object. Bailing out."); + return null; } - // The path argument is an array of [Step, Value] tuples. - // If Step === Step.NEIGHBOR, Value is the exact 16-bit hash query. - // If Step === Step.POINTER, Value is a random UInt32 seed used to calculate an aligned offset. - function evaluateTraversalPath(addr, path) { - let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); - print("Corrupting memory starting from object at 0x" + addr.toString(16) + " of type " + instanceType); - - for (let [stepType, seedValue] of path) { - if (!Sandbox.isWritableObjectAt(addr)) { - print(" Not corrupting read-only object. Bailing out."); - return null; + switch (stepType) { + case Step.NEIGHBOR: { + let oldAddr = addr; + addr = findRandomNeighborObject(addr, seedValue); + print(" Jumping to neighboring object at offset " + (addr - oldAddr)); + break; + } + case Step.POINTER: { + let offset = getRandomAlignedOffset(addr, seedValue); + let oldValue = memory.read(addr + offset, 32); + + // If the selected offset doesn't contain a valid pointer, we break out + // of the traversal loop but still corrupt the current (valid) object. + let isLikelyPointer = (oldValue & kHeapObjectTag) == kHeapObjectTag; + if (!isLikelyPointer) { + break; + } + + let newAddr = Number(oldValue & ~kHeapObjectTagMask); + if (!Sandbox.isValidObjectAt(newAddr)) { + break; } - switch (stepType) { - case Step.NEIGHBOR: { - let oldAddr = addr; - addr = findRandomNeighborObject(addr, seedValue); - print(" Jumping to neighboring object at offset " + (addr - oldAddr)); - break; - } - case Step.POINTER: { - let offset = getRandomAlignedOffset(addr, seedValue); - let oldValue = memory.read(addr + offset, 32); - - // If the selected offset doesn't contain a valid pointer, we break out - // of the traversal loop but still corrupt the current (valid) object. - let isLikelyPointer = (oldValue & kHeapObjectTag) == kHeapObjectTag; - if (!isLikelyPointer) { - break; - } - - let newAddr = Number(oldValue & ~kHeapObjectTagMask); - if (!Sandbox.isValidObjectAt(newAddr)) { - break; - } - - print(" Following pointer at offset " + offset + " to object at 0x" + newAddr.toString(16)); - - if (!Sandbox.isWritableObjectAt(newAddr)) { - newAddr = copyObjectAt(newAddr); - memory.write(addr + offset, BigInt(newAddr) | kHeapObjectTag, 32); - print(" Referenced object is in read-only memory. Created and linked a writable copy at 0x" + newAddr.toString(16)); - } - addr = newAddr; - break; - } + print(" Following pointer at offset " + offset + " to object at 0x" + newAddr.toString(16)); + + if (!Sandbox.isWritableObjectAt(newAddr)) { + newAddr = copyObjectAt(newAddr); + memory.write(addr + offset, BigInt(newAddr) | kHeapObjectTag, 32); + print(" Referenced object is in read-only memory. Created and linked a writable copy at 0x" + newAddr.toString(16)); } + addr = newAddr; + break; } - return Sandbox.isWritableObjectAt(addr) ? addr : null; } - - return { - builtins, getBaseAddress, evaluateTraversalPath, prepareDataCorruptionContext - }; } + return Sandbox.isWritableObjectAt(addr) ? addr : null; + } - function corruptDataWithBitflip(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + return { + builtins, getBaseAddress, evaluateTraversalPath, prepareDataCorruptionContext + }; + } - let newValue = oldValue ^ (1n << BigInt(bitPosition)); - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Bitflip"); - } + function corruptDataWithBitflip(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - function corruptDataWithIncrement(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, incrementValue) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + let newValue = oldValue ^ (1n << BigInt(bitPosition)); + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Bitflip"); + } - let newValue = (oldValue + incrementValue) & ((1n << BigInt(numBitsToCorrupt)) - 1n); - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Increment"); - } + function corruptDataWithIncrement(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, incrementValue) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; + + let newValue = (oldValue + incrementValue) & ((1n << BigInt(numBitsToCorrupt)) - 1n); + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Increment"); + } - function corruptDataWithReplace(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, replaceValue) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + function corruptDataWithReplace(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, replaceValue) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - let newValue = replaceValue; - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Replace"); - } + let newValue = replaceValue; + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Replace"); + } - function corruptWithWorker(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { - let { addr, offset, oldValue } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + function corruptWithWorker(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { + let { addr, offset, oldValue } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - let newValue = oldValue ^ (1n << BigInt(bitPosition)); + let newValue = oldValue ^ (1n << BigInt(bitPosition)); - globalThis.memory_corruption_worker.postMessage({ - address: addr + offset, valueA: Number(oldValue), valueB: Number(newValue), size: numBitsToCorrupt - }); + globalThis.memory_corruption_worker.postMessage({ + address: addr + offset, valueA: Number(oldValue), valueB: Number(newValue), size: numBitsToCorrupt + }); - print(" Started background worker to continuously flip " + numBitsToCorrupt + "-bit field at offset " + offset + " between 0x" + oldValue.toString(16) + " and 0x" + newValue.toString(16)); - } + print(" Started background worker to continuously flip " + numBitsToCorrupt + "-bit field at offset " + offset + " between 0x" + oldValue.toString(16) + " and 0x" + newValue.toString(16)); + } - function corruptFunction(obj, path, builtinSeed) { - let { builtins, getBaseAddress, evaluateTraversalPath } = getSandboxCorruptionHelpers(); - let baseAddr = getBaseAddress(obj); - if (!baseAddr) return; - let addr = evaluateTraversalPath(baseAddr, path); - if (!addr) return; - - let instanceTypeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); - if (instanceTypeId === Sandbox.getInstanceTypeIdFor("JS_FUNCTION_TYPE")) { - let targetObj = Sandbox.getObjectAt(addr); - let builtinId = builtinSeed % builtins.length; - try { - Sandbox.setFunctionCodeToBuiltin(targetObj, builtinId); - print(" Hijacked JSFunction code pointer! Swapped with builtin: " + builtins[builtinId]); - } catch(e) {} - } - } - """, + function corruptFunction(obj, path, builtinSeed) { + let { builtins, getBaseAddress, evaluateTraversalPath } = getSandboxCorruptionHelpers(); + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return; + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return; + + let instanceTypeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); + if (instanceTypeId === Sandbox.getInstanceTypeIdFor("JS_FUNCTION_TYPE")) { + let targetObj = Sandbox.getObjectAt(addr); + let builtinId = builtinSeed % builtins.length; + try { + Sandbox.setFunctionCodeToBuiltin(targetObj, builtinId); + print(" Hijacked JSFunction code pointer! Swapped with builtin: " + builtins[builtinId]); + } catch(e) {} + } + } + """, ecmaVersion: ECMAScriptVersion.es6, @@ -543,18 +550,18 @@ let v8SandboxProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (V8GcGenerator, 10), - (WasmStructGenerator, 5), - (WasmArrayGenerator, 5), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 5), - (HoleNanGenerator, 5), - (UndefinedNanGenerator, 5), - (StringShapeGenerator, 5), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (V8GcGenerator, 10), + (WasmStructGenerator, 5), + (WasmArrayGenerator, 5), + (SharedObjectGenerator, 5), + (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), ], additionalProgramTemplates: WeightedList([ @@ -566,9 +573,10 @@ let v8SandboxProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .object(), - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .object(), + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], @@ -577,4 +585,3 @@ let v8SandboxProfile = Profile( optionalPostProcessor: SandboxFuzzingPostProcessor() ) - diff --git a/Sources/Fuzzilli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift index 8037aca28..c7407040d 100644 --- a/Sources/Fuzzilli/Profiles/XSProfile.swift +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.function())) { b, f in +private let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.function())) { b, f in let arguments = b.randomArguments(forCalling: f) let index = b.loadInt(1) let end = b.loadInt(128) let gc = b.createNamedVariable(forBuiltin: "gc") b.callFunction(gc, withArgs: [index]) - b.buildWhileLoop({b.compare(index, with: end, using: .lessThan)}) { + b.buildWhileLoop({ b.compare(index, with: end, using: .lessThan) }) { b.callFunction(f, withArgs: arguments) b.unary(.PostInc, index) let result = b.callFunction(gc, withArgs: [index]) @@ -30,24 +29,26 @@ fileprivate let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.func } } -fileprivate let StressXSMemoryFail = CodeGenerator("StressXSMemoryFail", inputs: .required(.function())) { b, f in +private let StressXSMemoryFail = CodeGenerator("StressXSMemoryFail", inputs: .required(.function())) +{ b, f in let arguments = b.randomArguments(forCalling: f) let index = b.loadInt(1) - let max = b.loadInt(1000000) + let max = b.loadInt(1_000_000) let memoryFail = b.createNamedVariable(forBuiltin: "memoryFail") - b.callFunction(memoryFail, withArgs: [max]) // count how many allocations this function makes + b.callFunction(memoryFail, withArgs: [max]) // count how many allocations this function makes b.callFunction(f, withArgs: arguments) var end = b.callFunction(memoryFail, withArgs: [index]) end = b.binary(max, end, with: .Sub) - b.buildWhileLoop({b.compare(index, with: end, using: .lessThan)}) { + b.buildWhileLoop({ b.compare(index, with: end, using: .lessThan) }) { b.callFunction(f, withArgs: arguments) b.unary(.PostInc, index) b.callFunction(memoryFail, withArgs: [index]) } } -fileprivate let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { b, obj in +private let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { + b, obj in let harden = b.createNamedVariable(forBuiltin: "harden") if probability(0.05) { @@ -57,20 +58,20 @@ fileprivate let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .requ b.callFunction(harden, withArgs: [obj]) } -fileprivate let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in +private let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in let moduleSourceConstructor = b.createNamedVariable(forBuiltin: "ModuleSource") - let code = b.buildCodeString() { + let code = b.buildCodeString { b.build(n: 5) } b.construct(moduleSourceConstructor, withArgs: [code]) } -fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b in +private let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b in let compartmentConstructor = b.createNamedVariable(forBuiltin: "Compartment") - var endowments = [String: Variable]() // may be used as endowments argument or globalLexicals + var endowments = [String: Variable]() // may be used as endowments argument or globalLexicals var moduleMap = [String: Variable]() var options = [String: Variable]() @@ -80,7 +81,7 @@ fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b } var endowmentsObject = b.createObject(with: endowments) - // to do: populate moduleMap + // to do: populate moduleMap let moduleMapObject = b.createObject(with: moduleMap) let resolveHook = b.buildPlainFunction(with: .parameters(n: 2)) { _ in b.build(n: 5) @@ -106,17 +107,18 @@ fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b } let optionsObject = b.createObject(with: options) - let compartment = b.construct(compartmentConstructor, withArgs: [endowmentsObject, moduleMapObject, optionsObject]) + let compartment = b.construct( + compartmentConstructor, withArgs: [endowmentsObject, moduleMapObject, optionsObject]) if probability(0.5) { - let code = b.buildCodeString() { + let code = b.buildCodeString { b.build(n: 5) } b.callMethod("evaluate", on: compartment, withArgs: [code]) } } -fileprivate let UnicodeStringGenerator = CodeGenerator("UnicodeStringGenerator") { b in +private let UnicodeStringGenerator = CodeGenerator("UnicodeStringGenerator") { b in var s = "" for _ in 0.. 'X'", - "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", - "() => 42" + "'X'", + "'$1$2$3'", + "'$$$&$`$\\'$1'", + "() => 'X'", + "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", + "() => 42", ] let lastIndices = [ - "undefined", "-1", "0", - "1", "2", "3", - "4", "5", "6", - "7", "8", "9", - "50", "4294967296", "2147483647", - "2147483648", "NaN", "Not a Number" + "undefined", "-1", "0", + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", + "50", "4294967296", "2147483647", + "2147483648", "NaN", "Not a Number", ] let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -177,46 +181,61 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let resultVar = b.loadNull() - b.buildTryCatchFinally(tryBody: { - let symbol = b.createNamedVariable(forBuiltin: "Symbol") - withEqualProbability({ - let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("replace", of: symbol) - let replacement = withEqualProbability({ - b.loadString(b.randomString()) - }, { - b.loadString(chooseUniform(from: replacementCandidates)) - }) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("split", of: symbol) - let randomSplitLimit = withEqualProbability({ - "undefined" - }, { - "'not a number'" - }, { - String(b.randomInt()) - }) - let limit = b.loadString(randomSplitLimit) - let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(variable: resultVar, value: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) + b.buildTryCatchFinally( + tryBody: { + let symbol = b.createNamedVariable(forBuiltin: "Symbol") + withEqualProbability( + { + let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("match", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("replace", of: symbol) + let replacement = withEqualProbability( + { + b.loadString(b.randomString()) + }, + { + b.loadString(chooseUniform(from: replacementCandidates)) + }) + let res = b.callComputedMethod( + prop, on: regExpVar, withArgs: [subjectVar, replacement]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("search", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("split", of: symbol) + let randomSplitLimit = withEqualProbability( + { + "undefined" + }, + { + "'not a number'" + }, + { + String(b.randomInt()) + }) + let limit = b.loadString(randomSplitLimit) + let res = b.callComputedMethod( + symbol, on: regExpVar, withArgs: [subjectVar, limit]) + b.reassign(variable: resultVar, value: res) + }, + { + let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }) + }, + catchBody: { _ in }) - }, catchBody: { _ in - }) b.build(n: 7) @@ -228,15 +247,23 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.build(n: 15) } -public extension ILType { +extension ILType { /// Type of a JavaScript Compartment object. - static let jsCompartment = ILType.object(ofGroup: "Compartment", withProperties: ["globalThis"], withMethods: ["evaluate", "import", "importNow" /* , "module" */]) + public static let jsCompartment = ILType.object( + ofGroup: "Compartment", withProperties: ["globalThis"], + withMethods: ["evaluate", "import", "importNow" /* , "module" */]) - static let jsCompartmentConstructor = ILType.constructor([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartment) + .object(ofGroup: "CompartmentConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsCompartmentConstructor = + ILType.constructor([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartment) + + .object(ofGroup: "CompartmentConstructor", withProperties: ["prototype"], withMethods: []) - static let jsModuleSource = ILType.object(ofGroup: "ModuleSource", withProperties: ["bindings", "needsImport", "needsImportMeta"]) + public static let jsModuleSource = ILType.object( + ofGroup: "ModuleSource", withProperties: ["bindings", "needsImport", "needsImportMeta"]) - static let jsModuleSourceConstructor = ILType.constructor([.opt(.string)] => .jsModuleSource) + .object(ofGroup: "ModuleSourceConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsModuleSourceConstructor = + ILType.constructor([.opt(.string)] => .jsModuleSource) + + .object( + ofGroup: "ModuleSourceConstructor", withProperties: ["prototype"], withMethods: []) } /// Object group modelling JavaScript compartments. @@ -244,13 +271,13 @@ let jsCompartments = ObjectGroup( name: "Compartment", instanceType: .jsCompartment, properties: [ - "globalThis" : .object() + "globalThis": .object() ], methods: [ //@@ import/importNow can accept more than strings - "import" : [.string] => .jsPromise, - "importNow" : [.string] => .jsAnything, + "import": [.string] => .jsPromise, + "importNow": [.string] => .jsAnything, // "module" : [.opt(.string)] => .object(), (currently unavailable) - "evaluate" : [.string] => .jsAnything, + "evaluate": [.string] => .jsAnything, ] ) @@ -258,7 +285,7 @@ let jsCompartmentConstructor = ObjectGroup( name: "CompartmentConstructor", instanceType: .jsCompartmentConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) @@ -268,9 +295,9 @@ let jsModuleSources = ObjectGroup( name: "ModuleSource", instanceType: .jsModuleSource, properties: [ - "bindings" : .object(), - "needsImport" : .object(), - "needsImportMeta" : .object(), + "bindings": .object(), + "needsImport": .object(), + "needsImportMeta": .object(), ], methods: [:] ) @@ -279,7 +306,7 @@ let jsModuleSourceConstructor = ObjectGroup( name: "ModuleSourceConstructor", instanceType: .jsModuleSourceConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) @@ -291,21 +318,23 @@ let xsProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0:symbolize=1:print_stacktrace=1:silence_unsigned_overflow=1", - "ASAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", - "MSAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", - "MSAN_SYMBOLIZER_PATH": "/usr/bin/llvm-symbolizer"], + processEnv: [ + "UBSAN_OPTIONS": "handle_segv=0:symbolize=1:print_stacktrace=1:silence_unsigned_overflow=1", + "ASAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", + "MSAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", + "MSAN_SYMBOLIZER_PATH": "/usr/bin/llvm-symbolizer", + ], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -320,17 +349,17 @@ let xsProfile = Profile( ], additionalCodeGenerators: [ - (StressXSMemoryFail, 5), - (StressXSGC, 5), - (HardenGenerator, 5), - (CompartmentGenerator, 5), - (CompartmentEvaluateGenerator, 5), - (UnicodeStringGenerator, 2), - (ModuleSourceGenerator, 3), + (StressXSMemoryFail, 5), + (StressXSGC, 5), + (HardenGenerator, 5), + (CompartmentGenerator, 5), + (CompartmentEvaluateGenerator, 5), + (UnicodeStringGenerator, 2), + (ModuleSourceGenerator, 3), ], additionalProgramTemplates: WeightedList([ - (RegExpFuzzer, 1), + (RegExpFuzzer, 1) ]), disabledCodeGenerators: [], @@ -338,20 +367,23 @@ let xsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "memoryFail" : .function([.number] => .number), - "print" : .function([.string] => .undefined), + "gc": .function([] => .undefined), + "memoryFail": .function([.number] => .number), + "print": .function([.string] => .undefined), // hardened javascript - "Compartment" : .function([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartmentConstructor), - "ModuleSource" : .function([.opt(.string)] => .jsModuleSourceConstructor), - "harden" : .function([.object()] => .object()), - "lockdown" : .function([] => .undefined) , - "petrify" : .function([.jsAnything] => .jsAnything), - "mutabilities" : .function([.object()] => .object()) + "Compartment": .function( + [.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartmentConstructor), + "ModuleSource": .function([.opt(.string)] => .jsModuleSourceConstructor), + "harden": .function([.object()] => .object()), + "lockdown": .function([] => .undefined), + "petrify": .function([.jsAnything] => .jsAnything), + "mutabilities": .function([.object()] => .object()), ], - additionalObjectGroups: [jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor], + additionalObjectGroups: [ + jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor, + ], additionalEnumerations: [], diff --git a/Sources/Fuzzilli/Protobuf/ProtoUtils.swift b/Sources/Fuzzilli/Protobuf/ProtoUtils.swift index 488e43639..0852e154f 100644 --- a/Sources/Fuzzilli/Protobuf/ProtoUtils.swift +++ b/Sources/Fuzzilli/Protobuf/ProtoUtils.swift @@ -71,7 +71,8 @@ class ProtoCache { typealias OperationCache = ProtoCache -public func encodeProtobufCorpus(_ programs: T) throws -> Data where T.Element == Program { +public func encodeProtobufCorpus(_ programs: T) throws -> Data +where T.Element == Program { // This does streaming serialization to keep memory usage as low as possible. // Also, this uses the operation compression feature of our protobuf representation: // when the same operation occurs multiple times in the corpus, every subsequent @@ -99,19 +100,21 @@ public func encodeProtobufCorpus(_ programs: T) throws -> Data wh return buf } -public func decodeProtobufCorpus(_ buffer: Data) throws -> [Program]{ +public func decodeProtobufCorpus(_ buffer: Data) throws -> [Program] { let opCache = OperationCache.forDecoding() var offset = buffer.startIndex var newPrograms = [Program]() while offset + 4 <= buffer.endIndex { - let value = buffer.withUnsafeBytes { $0.load(fromByteOffset: offset - buffer.startIndex, as: UInt32.self) } + let value = buffer.withUnsafeBytes { + $0.load(fromByteOffset: offset - buffer.startIndex, as: UInt32.self) + } let size = Int(UInt32(littleEndian: value)) offset += 4 guard offset + size <= buffer.endIndex else { throw FuzzilliError.corpusImportError("Serialized corpus appears to be corrupted") } - let data = buffer.subdata(in: offset.. UnsafeMutablePointer?> { let buffer = UnsafeMutablePointer?>.allocate(capacity: array.count + 1) for (i, str) in array.enumerated() { -#if os(Windows) - buffer[i] = UnsafePointer(str.withCString(_strdup)) -#else - buffer[i] = UnsafePointer(str.withCString(strdup)) -#endif + #if os(Windows) + buffer[i] = UnsafePointer(str.withCString(_strdup)) + #else + buffer[i] = UnsafePointer(str.withCString(strdup)) + #endif } buffer[array.count] = nil return buffer } func freeCArray(_ array: UnsafeMutablePointer?>, numElems: Int) { - for arg in array ..< array + numElems { + for arg in array.. Result { - return try execute(executablePath, withInput: prefix + script.data(using: .utf8)!, withArguments: self.arguments, withEnv: self.env, timeout: timeout) + public func executeScript(_ script: String, withTimeout timeout: TimeInterval? = nil) throws + -> Result + { + return try execute( + executablePath, withInput: prefix + script.data(using: .utf8)!, + withArguments: self.arguments, withEnv: self.env, timeout: timeout) } /// Executes the JavaScript script at the specified path using the configured engine and returns the stdout. - public func executeScript(at url: URL, withTimeout timeout: TimeInterval? = nil) throws -> Result { + public func executeScript(at url: URL, withTimeout timeout: TimeInterval? = nil) throws + -> Result + { let script = try Data(contentsOf: url) - return try execute(executablePath, withInput: prefix + script, withArguments: self.arguments, withEnv: self.env, timeout: timeout) + return try execute( + executablePath, withInput: prefix + script, withArguments: self.arguments, + withEnv: self.env, timeout: timeout) } - func execute(_ path: String, withInput input: Data = Data(), withArguments arguments: [String] = [], withEnv env: [(String, String)] = [], timeout maybeTimeout: TimeInterval? = nil) throws -> Result { + func execute( + _ path: String, withInput input: Data = Data(), withArguments arguments: [String] = [], + withEnv env: [(String, String)] = [], timeout maybeTimeout: TimeInterval? = nil + ) throws -> Result { let inputPipe = Pipe() let outputPipe = Pipe() let errorPipe = Pipe() @@ -115,14 +133,15 @@ public class JavaScriptExecutor { // Write input into file. let url = FileManager.default.temporaryDirectory - .appendingPathComponent(UUID().uuidString) - .appendingPathExtension("js") + .appendingPathComponent(UUID().uuidString) + .appendingPathExtension("js") try input.write(to: url) // Close stdin try inputPipe.fileHandleForWriting.close() - let environment = ProcessInfo.processInfo.environment.merging(env, uniquingKeysWith: { _, new in new }) + let environment = ProcessInfo.processInfo.environment.merging( + env, uniquingKeysWith: { _, new in new }) // Execute the subprocess. let task = Process() @@ -145,19 +164,22 @@ public class JavaScriptExecutor { } runningCheck: if task.isRunning { timedOut = true -#if os(Windows) - guard let processHandle = OpenProcess(DWORD(PROCESS_TERMINATE), false, DWORD(task.processIdentifier)) else { - // Fall back to built-in termination - task.terminate() - break runningCheck - } - defer { CloseHandle(processHandle) } - TerminateProcess(processHandle, 1) -#else - // Properly kill the task now with SIGKILL as it might be stuck - // in Wasm, where SIGTERM is not enough. - kill(task.processIdentifier, SIGKILL) -#endif /* os(Windows) */ + #if os(Windows) + guard + let processHandle = OpenProcess( + DWORD(PROCESS_TERMINATE), false, DWORD(task.processIdentifier)) + else { + // Fall back to built-in termination + task.terminate() + break runningCheck + } + defer { CloseHandle(processHandle) } + TerminateProcess(processHandle, 1) + #else + // Properly kill the task now with SIGKILL as it might be stuck + // in Wasm, where SIGTERM is not enough. + kill(task.processIdentifier, SIGKILL) + #endif /* os(Windows) */ } } @@ -167,9 +189,11 @@ public class JavaScriptExecutor { try FileManager.default.removeItem(at: url) // Fetch and return the output. - var output = String(data: outputData.currentData, encoding: .utf8) + var output = + String(data: outputData.currentData, encoding: .utf8) ?? "Process output is not valid UTF-8" - let error = String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + let error = + String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? "Process stderr is not valid UTF-8" let outcome: Result.Outcome if timedOut { diff --git a/Sources/Fuzzilli/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift index bd524bcf2..91d118707 100644 --- a/Sources/Fuzzilli/Util/MockFuzzer.swift +++ b/Sources/Fuzzilli/Util/MockFuzzer.swift @@ -29,11 +29,12 @@ class MockScriptRunner: ScriptRunner { var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { - return MockExecution(outcome: .succeeded, - stdout: "", - stderr: "", - fuzzout: "", - execTime: TimeInterval(0.1)) + return MockExecution( + outcome: .succeeded, + stdout: "", + stderr: "", + fuzzout: "", + execTime: TimeInterval(0.1)) } func setEnvironmentVariable(_ key: String, to value: String) {} @@ -74,7 +75,9 @@ class MockEvaluator: ProgramEvaluator { func importState(_ state: Data) {} - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { return nil } @@ -82,7 +85,14 @@ class MockEvaluator: ProgramEvaluator { } /// Create a fuzzer instance usable for testing. -public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engine maybeEngine: FuzzEngine? = nil, runner maybeRunner: ScriptRunner? = nil, environment maybeEnvironment: JavaScriptEnvironment? = nil, evaluator maybeEvaluator: ProgramEvaluator? = nil, corpus maybeCorpus: Corpus? = nil, codeGenerators additionalCodeGenerators : [(CodeGenerator, Int)] = [], queue: DispatchQueue? = nil, overwriteGenerators: WeightedList? = nil) -> Fuzzer { +public func makeMockFuzzer( + config maybeConfiguration: Configuration? = nil, engine maybeEngine: FuzzEngine? = nil, + runner maybeRunner: ScriptRunner? = nil, + environment maybeEnvironment: JavaScriptEnvironment? = nil, + evaluator maybeEvaluator: ProgramEvaluator? = nil, corpus maybeCorpus: Corpus? = nil, + codeGenerators additionalCodeGenerators: [(CodeGenerator, Int)] = [], + queue: DispatchQueue? = nil, overwriteGenerators: WeightedList? = nil +) -> Fuzzer { // The configuration of this fuzzer. let configuration = maybeConfiguration ?? Configuration(logLevel: .warning) @@ -91,10 +101,10 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // the mutators to use for this fuzzing engine. let mutators = WeightedList([ - (CodeGenMutator(), 1), - (OperationMutator(), 1), + (CodeGenMutator(), 1), + (OperationMutator(), 1), (InputMutator(typeAwareness: .loose), 1), - (CombineMutator(), 1), + (CombineMutator(), 1), ]) let engine = maybeEngine ?? MutationEngine(numConsecutiveMutations: 5) @@ -106,7 +116,9 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi let environment = maybeEnvironment ?? JavaScriptEnvironment() // A lifter to translate FuzzIL programs to JavaScript. - let lifter = JavaScriptLifter(prefix: "", suffix: "", ecmaVersion: .es6, environment: environment, alwaysEmitVariables: configuration.forDifferentialFuzzing) + let lifter = JavaScriptLifter( + prefix: "", suffix: "", ecmaVersion: .es6, environment: environment, + alwaysEmitVariables: configuration.forDifferentialFuzzing) // Corpus managing interesting programs that have been found during fuzzing. let corpus = maybeCorpus ?? BasicCorpus(minSize: 1000, maxSize: 2000, minMutationsPerSample: 5) @@ -115,33 +127,38 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi let minimizer = Minimizer() // Use all builtin CodeGenerators - let codeGenerators = overwriteGenerators ?? WeightedList( - (CodeGenerators + WasmCodeGenerators).map { - guard let weight = codeGeneratorWeights[$0.name] else { - fatalError("Missing weight for CodeGenerator \($0.name) in CodeGeneratorWeights.swift") - } - return ($0, weight) - } + additionalCodeGenerators) + let codeGenerators = + overwriteGenerators + ?? WeightedList( + (CodeGenerators + WasmCodeGenerators).map { + guard let weight = codeGeneratorWeights[$0.name] else { + fatalError( + "Missing weight for CodeGenerator \($0.name) in CodeGeneratorWeights.swift") + } + return ($0, weight) + } + additionalCodeGenerators) // Use all builtin ProgramTemplates - let programTemplates = WeightedList(ProgramTemplates.map { return ($0, programTemplateWeights[$0.name]!) }) + let programTemplates = WeightedList( + ProgramTemplates.map { return ($0, programTemplateWeights[$0.name]!) }) // Construct the fuzzer instance. - let fuzzer = Fuzzer(configuration: configuration, - scriptRunner: runner, - referenceScriptRunner: nil, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, - programTemplates: programTemplates, - evaluator: evaluator, - environment: environment, - lifter: lifter, - corpus: corpus, - minimizer: minimizer, - queue: queue ?? DispatchQueue.main) - - let initializeFuzzer = { + let fuzzer = Fuzzer( + configuration: configuration, + scriptRunner: runner, + referenceScriptRunner: nil, + engine: engine, + mutators: mutators, + codeGenerators: codeGenerators, + programTemplates: programTemplates, + evaluator: evaluator, + environment: environment, + lifter: lifter, + corpus: corpus, + minimizer: minimizer, + queue: queue ?? DispatchQueue.main) + + let initializeFuzzer = { fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in print("[\(ev.label)] \(ev.message)") } @@ -151,7 +168,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // If a DispatchQueue was provided by the caller, initialize the fuzzer // there. Otherwise initialize it directly. if let queue { - queue.sync {initializeFuzzer()} + queue.sync { initializeFuzzer() } } else { dispatchPrecondition(condition: .onQueue(DispatchQueue.main)) initializeFuzzer() diff --git a/Sources/Fuzzilli/Util/Random.swift b/Sources/Fuzzilli/Util/Random.swift index 9b0a7eae6..097790d6f 100644 --- a/Sources/Fuzzilli/Util/Random.swift +++ b/Sources/Fuzzilli/Util/Random.swift @@ -43,9 +43,11 @@ extension Int { extension String { // Returns a random string of the specified length. - public static func random(ofLength length: Int, - withCharSet charSet: [Character] = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - ) -> String { + public static func random( + ofLength length: Int, + withCharSet charSet: [Character] = Array( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + ) -> String { var s = "" for _ in 0..: Sequence { } public func hasHoles() -> Bool { - return elements.contains(where: {$0 == nil}) + return elements.contains(where: { $0 == nil }) } public mutating func removeValue(forKey variable: Variable) { diff --git a/Sources/Fuzzilli/Util/VariableSet.swift b/Sources/Fuzzilli/Util/VariableSet.swift index aae322ef4..98131404a 100644 --- a/Sources/Fuzzilli/Util/VariableSet.swift +++ b/Sources/Fuzzilli/Util/VariableSet.swift @@ -222,7 +222,7 @@ public struct VariableSet: Hashable, Codable, Sequence { } /// Returns true if the two given sets are equal. - public static func ==(lhs: VariableSet, rhs: VariableSet) -> Bool { + public static func == (lhs: VariableSet, rhs: VariableSet) -> Bool { return lhs.words == rhs.words } diff --git a/Sources/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift index 7d8682088..a3c7e9fb0 100644 --- a/Sources/FuzzilliCli/TerminalUI.swift +++ b/Sources/FuzzilliCli/TerminalUI.swift @@ -17,8 +17,8 @@ import Fuzzilli let Seconds = 1.0 let Minutes = 60.0 * Seconds -let Hours = 60.0 * Minutes -let Days = 24.0 * Hours +let Hours = 60.0 * Minutes +let Days = 24.0 * Hours // A very basic terminal UI. class TerminalUI { @@ -44,11 +44,15 @@ class TerminalUI { fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in let color = self.colorForLevel[ev.level]! if ev.origin == fuzzer.id { - print("\u{001B}[0;\(color.rawValue)m[\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m") + print( + "\u{001B}[0;\(color.rawValue)m[\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m" + ) } else { // Mark message as coming from a worker by including its id let shortId = ev.origin.uuidString.split(separator: "-")[0] - print("\u{001B}[0;\(color.rawValue)m[\(shortId):\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m") + print( + "\u{001B}[0;\(color.rawValue)m[\(shortId):\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m" + ) } } @@ -74,7 +78,8 @@ class TerminalUI { } } - fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { program, origin in + fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { + program, origin in self.lastInterestingProgramFound = Date() if self.printNextInterestingProgram { print("--------- Randomly Sampled Interesting Program -----------") @@ -125,40 +130,43 @@ class TerminalUI { let timeSinceLastInterestingProgram = -lastInterestingProgramFound.timeIntervalSinceNow - let maybeAvgCorpusSize = stats.numChildNodes > 0 ? " (global average: \(Int(stats.avgCorpusSize)))" : "" + let maybeAvgCorpusSize = + stats.numChildNodes > 0 ? " (global average: \(Int(stats.avgCorpusSize)))" : "" if let tag = fuzzer.config.tag { print("Fuzzer Statistics (tag: \(tag))") } else { print("Fuzzer Statistics") } - let differentialsLine = fuzzer.isDifferentialFuzzing + let differentialsLine = + fuzzer.isDifferentialFuzzing ? "\nDifferentials Found: \(stats.differentialSamples)" : "" - print(""" - ----------------- - Fuzzer state: \(state) - Uptime: \(formatTimeInterval(fuzzer.uptime())) - Total Samples: \(stats.totalSamples) - Interesting Samples Found: \(stats.interestingSamples) - Last Interesting Sample: \(formatTimeInterval(timeSinceLastInterestingProgram)) - Valid Samples Found: \(stats.validSamples) - Corpus Size: \(fuzzer.corpus.size)\(maybeAvgCorpusSize) - Correctness Rate: \(String(format: "%.2f%%", stats.correctnessRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallCorrectnessRate * 100))) - Timeout Rate: \(String(format: "%.2f%%", stats.timeoutRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallTimeoutRate * 100))) - Crashes Found: \(stats.crashingSamples)\(differentialsLine) - Timeouts Hit: \(stats.timedOutSamples) - Coverage: \(String(format: "%.2f%%", stats.coverage * 100)) - Avg. program size: \(String(format: "%.2f", stats.avgProgramSize)) - Avg. corpus program size: \(String(format: "%.2f", stats.avgCorpusProgramSize)) - Avg. program execution time: \(Int(stats.avgExecutionTime * 1000))ms - Connected nodes: \(stats.numChildNodes) - Execs / Second: \(String(format: "%.2f", stats.execsPerSecond)) - Fuzzer Overhead: \(String(format: "%.2f", stats.fuzzerOverhead * 100))% - Minimization Overhead: \(String(format: "%.2f", stats.minimizationOverhead * 100))% - Total Execs: \(stats.totalExecs) - """) + print( + """ + ----------------- + Fuzzer state: \(state) + Uptime: \(formatTimeInterval(fuzzer.uptime())) + Total Samples: \(stats.totalSamples) + Interesting Samples Found: \(stats.interestingSamples) + Last Interesting Sample: \(formatTimeInterval(timeSinceLastInterestingProgram)) + Valid Samples Found: \(stats.validSamples) + Corpus Size: \(fuzzer.corpus.size)\(maybeAvgCorpusSize) + Correctness Rate: \(String(format: "%.2f%%", stats.correctnessRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallCorrectnessRate * 100))) + Timeout Rate: \(String(format: "%.2f%%", stats.timeoutRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallTimeoutRate * 100))) + Crashes Found: \(stats.crashingSamples)\(differentialsLine) + Timeouts Hit: \(stats.timedOutSamples) + Coverage: \(String(format: "%.2f%%", stats.coverage * 100)) + Avg. program size: \(String(format: "%.2f", stats.avgProgramSize)) + Avg. corpus program size: \(String(format: "%.2f", stats.avgCorpusProgramSize)) + Avg. program execution time: \(Int(stats.avgExecutionTime * 1000))ms + Connected nodes: \(stats.numChildNodes) + Execs / Second: \(String(format: "%.2f", stats.execsPerSecond)) + Fuzzer Overhead: \(String(format: "%.2f", stats.fuzzerOverhead * 100))% + Minimization Overhead: \(String(format: "%.2f", stats.minimizationOverhead * 100))% + Total Execs: \(stats.totalExecs) + """) } private func formatTimeInterval(_ interval: TimeInterval) -> String { @@ -170,23 +178,23 @@ class TerminalUI { } private enum Color: Int { - case reset = 0 - case black = 30 - case red = 31 - case green = 32 - case yellow = 33 - case blue = 34 + case reset = 0 + case black = 30 + case red = 31 + case green = 32 + case yellow = 33 + case blue = 34 case magenta = 35 - case cyan = 36 - case white = 37 + case cyan = 36 + case white = 37 } // The color with which to print log entries. private let colorForLevel: [LogLevel: Color] = [ .verbose: .cyan, - .info: .white, + .info: .white, .warning: .yellow, - .error: .red, - .fatal: .magenta + .error: .red, + .fatal: .magenta, ] } diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index f49dde3b6..8a95f081a 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -21,88 +21,89 @@ import Fuzzilli let args = Arguments.parse(from: CommandLine.arguments) if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != 1 { - print(""" -Usage: -\(args.programName) [options] --profile= /path/to/jsshell - -Options: - --profile=name : Select one of several preconfigured profiles. - Available profiles: \(profiles.keys). - --jobs=n : Total number of fuzzing jobs. This will start a main instance and n-1 worker instances. - --engine=name : The fuzzing engine to use. Available engines: "mutation" (default), "hybrid", "multi". - Only the mutation engine should be regarded stable at this point. - --corpus=name : The corpus scheduler to use. Available schedulers: "basic" (default), "markov" - --logLevel=level : The log level to use. Valid values: "verbose", "info", "warning", "error", "fatal" (default: "info"). - --maxIterations=n : Run for the specified number of iterations (default: unlimited). - --maxRuntimeInHours=n : Run for the specified number of hours (default: unlimited). - --timeout=n : Timeout in ms after which to interrupt execution of programs (default depends - on the profile). Or provide an interval like --timeout=200,400. The actual - timeout in this interval will be determined by the start-up tests. - --minMutationsPerSample=n : Discard samples from the corpus only after they have been mutated at least this many times (default: 25). - --minCorpusSize=n : Keep at least this many samples in the corpus regardless of the number of times - they have been mutated (default: 1000). - --maxCorpusSize=n : Only allow the corpus to grow to this many samples. Otherwise the oldest samples - will be discarded (default: unlimited). - --markovDropoutRate=p : Rate at which low edge samples are not selected, in the Markov Corpus Scheduler, - per round of sample selection. Used to ensure diversity between fuzzer instances - (default: 0.10) - --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). - --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions - regardless of whether they are needed to trigger the interesting behaviour or not. - See Minimizer.swift for an overview of this feature (default: 0.0). - --storagePath=path : Path at which to store output files (crashes, corpus, etc.) to. - --resume : If storage path exists, import the programs from the corpus/ subdirectory - --overwrite : If storage path exists, delete all data in it and start a fresh fuzzing session - --staticCorpus : In this mode, we will just mutate the existing corpus and look for crashes. - No new samples are added to the corpus, regardless of their coverage. - This can be used to find different manifestations of bugs and - also to try and reproduce a flaky crash or turn it into a deterministic one. - --exportStatistics : If enabled, fuzzing statistics will be collected and saved to disk in regular intervals. - Requires --storagePath. - --statisticsExportInterval=n : Interval in minutes for saving fuzzing statistics to disk (default: 10). - Requires --exportStatistics. - --importCorpus=path : Imports an existing corpus of FuzzIL programs to build the initial corpus for fuzzing. - The provided path must point to a directory, and all .fzil files in that directory will be imported. - --corpusImportMode=mode : The corpus import mode. Possible values: - default : Keep samples that are interesting (e.g. those that increase code coverage) and minimize them (default). - full : Keep all samples that execute successfully without minimization. - unminimized : Keep samples that are interesting but do not minimize them. - - --instanceType=type : Specifies the instance type for distributed fuzzing over a network. - In distributed fuzzing, instances form a tree hierarchy, so the possible values are: - root: Accept connections from other instances. - leaf: Connect to a parent instance and synchronize with it. - intermediate: Connect to a parent instance and synchronize with it but also accept incoming connections. - standalone: Don't participate in distributed fuzzing (default). - Note: it is *highly* recommended to run distributed fuzzing in an isolated network! - --bindTo=host:port : When running as a root or intermediate node, bind to this address (default: 127.0.0.1:1337). - --connectTo=host:port : When running as a leaf or intermediate node, connect to the parent instance at this address (default: 127.0.0.1:1337). - --corpusSyncMode=mode : How the corpus is synchronized during distributed fuzzing. Possible values: - up: newly discovered corpus samples are only sent to parent nodes but - not to chjild nodes. This way, the child nodes are forced to generate their - own corpus, which may lead to more diverse samples overall. However, parent - instances will still have the full corpus. - down: newly discovered corpus samples are only sent to child nodes but not to - parent nodes. This may make sense when importing a corpus in the parent. - full (default): newly discovered corpus samples are sent in both direction. This is the - default behaviour and will generally cause all instances in the network - to have very roughly the same corpus. - none : corpus samples are not shared with any other instances in the network. - Note: thread workers (--jobs=X) always fully synchronize their corpus. - --diagnostics : Enable saving of programs that failed or timed-out during execution. Also tracks - executions on the current REPRL instance. - --swarmTesting : Enable Swarm Testing mode. The fuzzer will choose random weights for the code generators per process. - --inspect : Enable inspection for generated programs. When enabled, additional .fuzzil.history files are written - to disk for every interesting or crashing program. These describe in detail how the program was generated - through mutations, code generation, and minimization. - --argumentRandomization : Enable JS engine argument randomization - --additionalArguments=args : Pass additional arguments to the JS engine. If multiple arguments are passed, they should be separated by a comma. - --tag=tag : Optional string tag associated with this instance which will be stored in the settings.json file as well as in crashing samples. - This can for example be used to remember the target revision that is being fuzzed. - --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). - --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. - -""") + print( + """ + Usage: + \(args.programName) [options] --profile= /path/to/jsshell + + Options: + --profile=name : Select one of several preconfigured profiles. + Available profiles: \(profiles.keys). + --jobs=n : Total number of fuzzing jobs. This will start a main instance and n-1 worker instances. + --engine=name : The fuzzing engine to use. Available engines: "mutation" (default), "hybrid", "multi". + Only the mutation engine should be regarded stable at this point. + --corpus=name : The corpus scheduler to use. Available schedulers: "basic" (default), "markov" + --logLevel=level : The log level to use. Valid values: "verbose", "info", "warning", "error", "fatal" (default: "info"). + --maxIterations=n : Run for the specified number of iterations (default: unlimited). + --maxRuntimeInHours=n : Run for the specified number of hours (default: unlimited). + --timeout=n : Timeout in ms after which to interrupt execution of programs (default depends + on the profile). Or provide an interval like --timeout=200,400. The actual + timeout in this interval will be determined by the start-up tests. + --minMutationsPerSample=n : Discard samples from the corpus only after they have been mutated at least this many times (default: 25). + --minCorpusSize=n : Keep at least this many samples in the corpus regardless of the number of times + they have been mutated (default: 1000). + --maxCorpusSize=n : Only allow the corpus to grow to this many samples. Otherwise the oldest samples + will be discarded (default: unlimited). + --markovDropoutRate=p : Rate at which low edge samples are not selected, in the Markov Corpus Scheduler, + per round of sample selection. Used to ensure diversity between fuzzer instances + (default: 0.10) + --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). + --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions + regardless of whether they are needed to trigger the interesting behaviour or not. + See Minimizer.swift for an overview of this feature (default: 0.0). + --storagePath=path : Path at which to store output files (crashes, corpus, etc.) to. + --resume : If storage path exists, import the programs from the corpus/ subdirectory + --overwrite : If storage path exists, delete all data in it and start a fresh fuzzing session + --staticCorpus : In this mode, we will just mutate the existing corpus and look for crashes. + No new samples are added to the corpus, regardless of their coverage. + This can be used to find different manifestations of bugs and + also to try and reproduce a flaky crash or turn it into a deterministic one. + --exportStatistics : If enabled, fuzzing statistics will be collected and saved to disk in regular intervals. + Requires --storagePath. + --statisticsExportInterval=n : Interval in minutes for saving fuzzing statistics to disk (default: 10). + Requires --exportStatistics. + --importCorpus=path : Imports an existing corpus of FuzzIL programs to build the initial corpus for fuzzing. + The provided path must point to a directory, and all .fzil files in that directory will be imported. + --corpusImportMode=mode : The corpus import mode. Possible values: + default : Keep samples that are interesting (e.g. those that increase code coverage) and minimize them (default). + full : Keep all samples that execute successfully without minimization. + unminimized : Keep samples that are interesting but do not minimize them. + + --instanceType=type : Specifies the instance type for distributed fuzzing over a network. + In distributed fuzzing, instances form a tree hierarchy, so the possible values are: + root: Accept connections from other instances. + leaf: Connect to a parent instance and synchronize with it. + intermediate: Connect to a parent instance and synchronize with it but also accept incoming connections. + standalone: Don't participate in distributed fuzzing (default). + Note: it is *highly* recommended to run distributed fuzzing in an isolated network! + --bindTo=host:port : When running as a root or intermediate node, bind to this address (default: 127.0.0.1:1337). + --connectTo=host:port : When running as a leaf or intermediate node, connect to the parent instance at this address (default: 127.0.0.1:1337). + --corpusSyncMode=mode : How the corpus is synchronized during distributed fuzzing. Possible values: + up: newly discovered corpus samples are only sent to parent nodes but + not to chjild nodes. This way, the child nodes are forced to generate their + own corpus, which may lead to more diverse samples overall. However, parent + instances will still have the full corpus. + down: newly discovered corpus samples are only sent to child nodes but not to + parent nodes. This may make sense when importing a corpus in the parent. + full (default): newly discovered corpus samples are sent in both direction. This is the + default behaviour and will generally cause all instances in the network + to have very roughly the same corpus. + none : corpus samples are not shared with any other instances in the network. + Note: thread workers (--jobs=X) always fully synchronize their corpus. + --diagnostics : Enable saving of programs that failed or timed-out during execution. Also tracks + executions on the current REPRL instance. + --swarmTesting : Enable Swarm Testing mode. The fuzzer will choose random weights for the code generators per process. + --inspect : Enable inspection for generated programs. When enabled, additional .fuzzil.history files are written + to disk for every interesting or crashing program. These describe in detail how the program was generated + through mutations, code generation, and minimization. + --argumentRandomization : Enable JS engine argument randomization + --additionalArguments=args : Pass additional arguments to the JS engine. If multiple arguments are passed, they should be separated by a comma. + --tag=tag : Optional string tag associated with this instance which will be stored in the settings.json file as well as in crashing samples. + This can for example be used to remember the target revision that is being fuzzed. + --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). + --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + + """) exit(0) } @@ -125,7 +126,9 @@ if let val = args["--profile"], let p = profiles[val] { profileName = val } if profile == nil || profileName == nil { - configError("Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)") + configError( + "Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)" + ) } let numJobs = args.int(for: "--jobs") ?? 1 @@ -159,12 +162,13 @@ let tag = args["--tag"] let enableWasm = args.has("--wasm") let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") -var timeout : Timeout +var timeout: Timeout if let raw_timeout = args.string(for: "--timeout") { if raw_timeout.contains(",") { let parts = raw_timeout.split(separator: ",") guard parts.count == 2 else { - configError("Timeout intervals must be specified by two boundaries, e.g. --timeout=200,400") + configError( + "Timeout intervals must be specified by two boundaries, e.g. --timeout=200,400") } guard let lower = UInt32(parts[0]) else { configError("The lower bound for --timeout must be an integer") @@ -200,7 +204,9 @@ if maxIterations != -1 { exitCondition = .timeFuzzed(Double(maxRuntimeInHours) * Hours) } -let logLevelByName: [String: LogLevel] = ["verbose": .verbose, "info": .info, "warning": .warning, "error": .error, "fatal": .fatal] +let logLevelByName: [String: LogLevel] = [ + "verbose": .verbose, "info": .info, "warning": .warning, "error": .error, "fatal": .fatal, +] guard let logLevel = logLevelByName[logLevelName] else { configError("Invalid log level \(logLevelName)") } @@ -223,9 +229,13 @@ if markovDropoutRate < 0 || markovDropoutRate > 1 { print("The markovDropoutRate must be between 0 and 1") } -if corpusName == "markov" && (args.int(for: "--maxCorpusSize") != nil || args.int(for: "--minCorpusSize") != nil - || args.int(for: "--minMutationsPerSample") != nil ) { - configError("--maxCorpusSize, --minCorpusSize, --minMutationsPerSample are not compatible with the Markov corpus") +if corpusName == "markov" + && (args.int(for: "--maxCorpusSize") != nil || args.int(for: "--minCorpusSize") != nil + || args.int(for: "--minMutationsPerSample") != nil) +{ + configError( + "--maxCorpusSize, --minCorpusSize, --minMutationsPerSample are not compatible with the Markov corpus" + ) } if (resume || overwrite) && storagePath == nil { @@ -239,7 +249,9 @@ if corpusName == "markov" && staticCorpus { if let path = storagePath { let directory = (try? FileManager.default.contentsOfDirectory(atPath: path)) ?? [] if !directory.isEmpty && !resume && !overwrite { - configError("Storage path \(path) exists and is not empty. Please specify either --resume or --overwrite or delete the directory manually") + configError( + "Storage path \(path) exists and is not empty. Please specify either --resume or --overwrite or delete the directory manually" + ) } } @@ -255,7 +267,7 @@ if statisticsExportInterval <= 0 { configError("statisticsExportInterval needs to be > 0") } -if args.has("--statisticsExportInterval") && !exportStatistics { +if args.has("--statisticsExportInterval") && !exportStatistics { configError("statisticsExportInterval requires --exportStatistics") } @@ -271,7 +283,10 @@ if minimizationLimit < 0 || minimizationLimit > 1 { configError("--minimizationLimit must be between 0 and 1") } -let corpusImportModeByName: [String: CorpusImportMode] = ["default": .interestingOnly(shouldMinimize: true), "full": .full, "unminimized": .interestingOnly(shouldMinimize: false)] +let corpusImportModeByName: [String: CorpusImportMode] = [ + "default": .interestingOnly(shouldMinimize: true), "full": .full, + "unminimized": .interestingOnly(shouldMinimize: false), +] guard let corpusImportMode = corpusImportModeByName[corpusImportModeName] else { configError("Invalid corpus import mode \(corpusImportModeName)") } @@ -314,13 +329,17 @@ func parseAddress(_ argName: String) -> (String, UInt16) { var addressToBindTo: (ip: String, port: UInt16) = parseAddress("--bindTo") var addressToConnectTo: (ip: String, port: UInt16) = parseAddress("--connectTo") -let corpusSyncModeByName: [String: CorpusSynchronizationMode] = ["up": .up, "down": .down, "full": .full, "none": .none] +let corpusSyncModeByName: [String: CorpusSynchronizationMode] = [ + "up": .up, "down": .down, "full": .full, "none": .none, +] guard let corpusSyncMode = corpusSyncModeByName[corpusSyncMode] else { configError("Invalid corpus synchronization mode \(corpusSyncMode)") } if staticCorpus && !(resume || isNetworkChildNode || corpusImportPath != nil) { - configError("Static corpus requires this instance to import a corpus or to participate in distributed fuzzing as a child node") + configError( + "Static corpus requires this instance to import a corpus or to participate in distributed fuzzing as a child node" + ) } // Make it easy to detect typos etc. in command line arguments @@ -347,12 +366,12 @@ if swarmTesting { let disableCodeGenerators = Set(profile.disabledCodeGenerators) let additionalCodeGenerators = profile.additionalCodeGenerators -let codeGeneratorsToUse = if enableWasm { - CodeGenerators + WasmCodeGenerators -} else { - CodeGenerators -} - +let codeGeneratorsToUse = + if enableWasm { + CodeGenerators + WasmCodeGenerators + } else { + CodeGenerators + } let standardCodeGenerators: [(CodeGenerator, Int)] = codeGeneratorsToUse.map { guard let weight = codeGeneratorWeights[$0.name] else { @@ -381,7 +400,8 @@ for (generator, var weight) in (additionalCodeGenerators + standardCodeGenerator func loadCorpus(from dirPath: String) -> [Program] { var isDir: ObjCBool = false - guard FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) && isDir.boolValue else { + guard FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) && isDir.boolValue + else { logger.fatal("Cannot import programs from \(dirPath), it is not a directory!") } @@ -408,12 +428,16 @@ func loadCorpus(from dirPath: String) -> [Program] { // When using multiple jobs, all Fuzzilli instances should use the same arguments for the JS shell, even if // argument randomization is enabled. This way, their corpora are "compatible" and crashes that require // (a subset of) the randomly chosen flags can be reproduced on the main instance. -let jsShellArguments = profile.processArgs(argumentRandomization) + additionalArguments.split(separator: ",").map(String.init) +let jsShellArguments = + profile.processArgs(argumentRandomization) + + additionalArguments.split(separator: ",").map(String.init) logger.info("Using the following arguments for the target engine: \(jsShellArguments)") func makeFuzzer(with configuration: Configuration) -> Fuzzer { let createRunner = { (baseArgs: [String], forReferenceRunner: Bool) -> REPRL in - let finalArgs = baseArgs + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) + let finalArgs = + baseArgs + + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) return REPRL( executable: jsShellPath, processArguments: finalArgs, @@ -436,29 +460,32 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { /// The mutation fuzzer responsible for mutating programs from the corpus and evaluating the outcome. let disabledMutators = Set(profile.disabledMutators) var mutators = WeightedList([ - (ExplorationMutator(), 3), - (CodeGenMutator(), 2), - (SpliceMutator(), 2), - (ProbingMutator(), 2), - (InputMutator(typeAwareness: .loose), 2), - (InputMutator(typeAwareness: .aware), 1), + (ExplorationMutator(), 3), + (CodeGenMutator(), 2), + (SpliceMutator(), 2), + (ProbingMutator(), 2), + (InputMutator(typeAwareness: .loose), 2), + (InputMutator(typeAwareness: .aware), 1), // Can be enabled for experimental use, ConcatMutator is a limited version of CombineMutator // (ConcatMutator(), 1), - (OperationMutator(), 1), - (CombineMutator(), 1), + (OperationMutator(), 1), + (CombineMutator(), 1), // Include this once it does more than just remove unneeded try-catch // (FixupMutator()), 1), ]) let mutatorsSet = Set(mutators.map { $0.name }) if !disabledMutators.isSubset(of: mutatorsSet) { - configError("The following mutators in \(profileName!) profile's disabledMutators do not exist: \(disabledMutators.subtracting(mutatorsSet)). Please check and remove them from your profile configuration.") + configError( + "The following mutators in \(profileName!) profile's disabledMutators do not exist: \(disabledMutators.subtracting(mutatorsSet)). Please check and remove them from your profile configuration." + ) } if !disabledMutators.isEmpty { mutators = mutators.filter({ !disabledMutators.contains($0.name) }) } logger.info("Enabled mutators: \(mutators.map { $0.name })") if mutators.isEmpty { - configError("List of enabled mutators is empty. There needs to be at least one mutator available.") + configError( + "List of enabled mutators is empty. There needs to be at least one mutator available.") } // Engines to execute programs. @@ -479,7 +506,8 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { // to minimize, making the fuzzer less efficient. // For the same reason, we also use a relatively larger iterationsPerEngine value, so that // the MutationEngine can already find most "low-hanging fruits" in its first run. - engine = MultiEngine(engines: engines, initialActive: mutationEngine, iterationsPerEngine: 10000) + engine = MultiEngine( + engines: engines, initialActive: mutationEngine, iterationsPerEngine: 10000) default: engine = MutationEngine(numConsecutiveMutations: consecutiveMutations) } @@ -494,7 +522,9 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { for template in ProgramTemplates { guard let weight = programTemplateWeights[template.name] else { - print("Missing weight for program template \(template.name) in ProgramTemplateWeights.swift") + print( + "Missing weight for program template \(template.name) in ProgramTemplateWeights.swift" + ) exit(-1) } @@ -509,23 +539,32 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { } // The environment containing available builtins, property names, and method names. - let environment = JavaScriptEnvironment(additionalBuiltins: profile.additionalBuiltins, additionalObjectGroups: profile.additionalObjectGroups, additionalEnumerations: profile.additionalEnumerations) + let environment = JavaScriptEnvironment( + additionalBuiltins: profile.additionalBuiltins, + additionalObjectGroups: profile.additionalObjectGroups, + additionalEnumerations: profile.additionalEnumerations) if !profile.additionalBuiltins.isEmpty { - logger.verbose("Loaded additional builtins from profile: \(profile.additionalBuiltins.map { $0.key })") + logger.verbose( + "Loaded additional builtins from profile: \(profile.additionalBuiltins.map { $0.key })") } if !profile.additionalObjectGroups.isEmpty { - logger.verbose("Loaded additional ObjectGroups from profile: \(profile.additionalObjectGroups.map { $0.name })") + logger.verbose( + "Loaded additional ObjectGroups from profile: \(profile.additionalObjectGroups.map { $0.name })" + ) } if !profile.additionalEnumerations.isEmpty { - logger.verbose("Loaded additional Enumerations from profile: \(profile.additionalEnumerations.map { $0.group! })") + logger.verbose( + "Loaded additional Enumerations from profile: \(profile.additionalEnumerations.map { $0.group! })" + ) } // A lifter to translate FuzzIL programs to JavaScript. - let lifter = JavaScriptLifter(prefix: profile.codePrefix, - suffix: profile.codeSuffix, - ecmaVersion: profile.ecmaVersion, - environment: environment, - alwaysEmitVariables: configuration.forDifferentialFuzzing) + let lifter = JavaScriptLifter( + prefix: profile.codePrefix, + suffix: profile.codeSuffix, + ecmaVersion: profile.ecmaVersion, + environment: environment, + alwaysEmitVariables: configuration.forDifferentialFuzzing) // The evaluator to score produced samples. let evaluator = ProgramCoverageEvaluator(runner: runner) @@ -534,9 +573,12 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let corpus: Corpus switch corpusName { case "basic": - corpus = BasicCorpus(minSize: minCorpusSize, maxSize: maxCorpusSize, minMutationsPerSample: minMutationsPerSample) + corpus = BasicCorpus( + minSize: minCorpusSize, maxSize: maxCorpusSize, + minMutationsPerSample: minMutationsPerSample) case "markov": - corpus = MarkovCorpus(covEvaluator: evaluator as ProgramCoverageEvaluator, dropoutRate: markovDropoutRate) + corpus = MarkovCorpus( + covEvaluator: evaluator as ProgramCoverageEvaluator, dropoutRate: markovDropoutRate) default: logger.fatal("Invalid corpus name provided") } @@ -545,35 +587,37 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let minimizer = Minimizer() // Construct the fuzzer instance. - return Fuzzer(configuration: configuration, - scriptRunner: runner, - referenceScriptRunner: referenceRunner, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, - programTemplates: programTemplates, - evaluator: evaluator, - environment: environment, - lifter: lifter, - corpus: corpus, - minimizer: minimizer) + return Fuzzer( + configuration: configuration, + scriptRunner: runner, + referenceScriptRunner: referenceRunner, + engine: engine, + mutators: mutators, + codeGenerators: codeGenerators, + programTemplates: programTemplates, + evaluator: evaluator, + environment: environment, + lifter: lifter, + corpus: corpus, + minimizer: minimizer) } // The configuration of the main fuzzer instance. -let mainConfig = Configuration(arguments: CommandLine.arguments, - timeout: timeout.maxTimeout(), - logLevel: logLevel, - startupTests: profile.startupTests, - minimizationLimit: minimizationLimit, - enableDiagnostics: diagnostics, - enableInspection: inspect, - staticCorpus: staticCorpus, - tag: tag, - isWasmEnabled: enableWasm, - storagePath: storagePath, - forDifferentialFuzzing: forDifferentialFuzzing, - instanceId: 0, - dumplingEnabled: profile.isDifferential) +let mainConfig = Configuration( + arguments: CommandLine.arguments, + timeout: timeout.maxTimeout(), + logLevel: logLevel, + startupTests: profile.startupTests, + minimizationLimit: minimizationLimit, + enableDiagnostics: diagnostics, + enableInspection: inspect, + staticCorpus: staticCorpus, + tag: tag, + isWasmEnabled: enableWasm, + storagePath: storagePath, + forDifferentialFuzzing: forDifferentialFuzzing, + instanceId: 0, + dumplingEnabled: profile.isDifferential) let fuzzer = makeFuzzer(with: mainConfig) @@ -607,12 +651,13 @@ fuzzer.sync { if resume, let path = storagePath { // Check if we have an old_corpus directory on disk, this can happen if the user Ctrl-C's during an import. if FileManager.default.fileExists(atPath: path + "/old_corpus") { - logger.info("Corpus import aborted. The old corpus is now in \(path + "/old_corpus").") + logger.info( + "Corpus import aborted. The old corpus is now in \(path + "/old_corpus").") logger.info("You can recover the old corpus by moving it to \(path + "/corpus").") } } let code = reason.toExitCode() - if (code != 0) { + if code != 0 { print("Aborting execution after a fatal error.") } exit(code) @@ -624,10 +669,13 @@ fuzzer.sync { // Move the old corpus to a new directory from which the files will be imported afterwards // before the directory is deleted. if FileManager.default.fileExists(atPath: path + "/old_corpus") { - logger.fatal("Unexpected /old_corpus directory found! Was a previous import aborted? Please check if you need to recover the old corpus manually by moving to to /corpus or deleting it.") + logger.fatal( + "Unexpected /old_corpus directory found! Was a previous import aborted? Please check if you need to recover the old corpus manually by moving to to /corpus or deleting it." + ) } do { - try FileManager.default.moveItem(atPath: path + "/corpus", toPath: path + "/old_corpus") + try FileManager.default.moveItem( + atPath: path + "/corpus", toPath: path + "/old_corpus") } catch { logger.info("Nothing to resume from: \(path)/corpus does not exist") resume = false @@ -637,22 +685,32 @@ fuzzer.sync { try? FileManager.default.removeItem(atPath: path) } else { // The corpus directory must be empty. We already checked this above, so just assert here - let directory = (try? FileManager.default.contentsOfDirectory(atPath: path + "/corpus")) ?? [] + let directory = + (try? FileManager.default.contentsOfDirectory(atPath: path + "/corpus")) ?? [] assert(directory.isEmpty) } - fuzzer.addModule(Storage(for: fuzzer, - storageDir: path, - statisticsExportInterval: exportStatistics ? Double(statisticsExportInterval) * Minutes : nil - )) + fuzzer.addModule( + Storage( + for: fuzzer, + storageDir: path, + statisticsExportInterval: exportStatistics + ? Double(statisticsExportInterval) * Minutes : nil + )) } // Synchronize over the network if requested. if isNetworkParentNode { - fuzzer.addModule(NetworkParent(for: fuzzer, address: addressToBindTo.ip, port: addressToBindTo.port, corpusSynchronizationMode: corpusSyncMode)) + fuzzer.addModule( + NetworkParent( + for: fuzzer, address: addressToBindTo.ip, port: addressToBindTo.port, + corpusSynchronizationMode: corpusSyncMode)) } if isNetworkChildNode { - fuzzer.addModule(NetworkChild(for: fuzzer, hostname: addressToConnectTo.ip, port: addressToConnectTo.port, corpusSynchronizationMode: corpusSyncMode)) + fuzzer.addModule( + NetworkChild( + for: fuzzer, hostname: addressToConnectTo.ip, port: addressToConnectTo.port, + corpusSynchronizationMode: corpusSyncMode)) } // Synchronize with thread workers if requested. @@ -679,8 +737,11 @@ fuzzer.sync { try? FileManager.default.removeItem(atPath: path + "/old_corpus") let duration = Date().timeIntervalSince(start) - let humanReadableDuration = Duration.seconds(duration).formatted(.time(pattern: .hourMinuteSecond)) - logger.info("Corpus import after resume took \((String(format: "%.0f", duration)))s (\(humanReadableDuration)).") + let humanReadableDuration = Duration.seconds(duration).formatted( + .time(pattern: .hourMinuteSecond)) + logger.info( + "Corpus import after resume took \((String(format: "%.0f", duration)))s (\(humanReadableDuration))." + ) } fuzzer.scheduleCorpusImport(corpus, importMode: .interestingOnly(shouldMinimize: false)) // We assume that the programs are already minimized @@ -694,12 +755,17 @@ fuzzer.sync { guard !corpus.isEmpty else { logger.fatal("Cannot import an empty corpus.") } - logger.info("Scheduling corpus import of \(corpus.count) programs with mode \(corpusImportModeName).") + logger.info( + "Scheduling corpus import of \(corpus.count) programs with mode \(corpusImportModeName)." + ) fuzzer.registerEventListener(for: fuzzer.events.CorpusImportComplete) { let duration = Date().timeIntervalSince(start) - let humanReadableDuration = Duration.seconds(duration).formatted(.time(pattern: .hourMinuteSecond)) - logger.info("Existing corpus import took \((String(format: "%.0f", duration)))s (\(humanReadableDuration)).") + let humanReadableDuration = Duration.seconds(duration).formatted( + .time(pattern: .hourMinuteSecond)) + logger.info( + "Existing corpus import took \((String(format: "%.0f", duration)))s (\(humanReadableDuration))." + ) } fuzzer.scheduleCorpusImport(corpus, importMode: corpusImportMode) @@ -716,20 +782,21 @@ fuzzer.sync { for i in 1.. /path/to/jsshell - - Options: - --profile=name : Select one of several preconfigured profiles. - Available profiles: \(profiles.keys). - --no-args : Invoke the shell without any additional arguments from the profile. - """) + print( + """ + Usage: + \(args.programName) [options] --profile= /path/to/jsshell + + Options: + --profile=name : Select one of several preconfigured profiles. + Available profiles: \(profiles.keys). + --no-args : Invoke the shell without any additional arguments from the profile. + """) exit(helpRequested ? 0 : -1) } guard let profileName = args["--profile"], let profile = profiles[profileName] else { - configError("Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)") + configError( + "Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)" + ) } let jsshellArguments = args.has("--no-args") ? [] : profile.processArgs(false) let runner = JavaScriptExecutor(withExecutablePath: args[0], arguments: jsshellArguments, env: []) let jsProg = """ -(function() { - const maxDepth = 10; // Limit the maximum recursion depth. - const seenObjects = new Map(); - let idCounter = 0; - const flatGraph = {}; - - function walk(currentObj, currentDepth) { - const isObjectOrFunction = currentObj !== null - && (typeof currentObj === 'object' || typeof currentObj === 'function'); - - // Deduplicate objects that appear multiple times in the graph. - if (seenObjects.has(currentObj)) { - return seenObjects.get(currentObj); - } + (function() { + const maxDepth = 10; // Limit the maximum recursion depth. + const seenObjects = new Map(); + let idCounter = 0; + const flatGraph = {}; + + function walk(currentObj, currentDepth) { + const isObjectOrFunction = currentObj !== null + && (typeof currentObj === 'object' || typeof currentObj === 'function'); + + // Deduplicate objects that appear multiple times in the graph. + if (seenObjects.has(currentObj)) { + return seenObjects.get(currentObj); + } - // Store current object for deduplication. - const currentId = idCounter++; - seenObjects.set(currentObj, currentId); - let typeLabel = typeof currentObj; - if (currentObj === null) typeLabel = "null"; - else if (Array.isArray(currentObj)) typeLabel = "array"; + // Store current object for deduplication. + const currentId = idCounter++; + seenObjects.set(currentObj, currentId); + let typeLabel = typeof currentObj; + if (currentObj === null) typeLabel = "null"; + else if (Array.isArray(currentObj)) typeLabel = "array"; - const node = { - type: typeLabel, - properties: {} - }; + const node = { + type: typeLabel, + properties: {} + }; - flatGraph[currentId] = node; + flatGraph[currentId] = node; - if (!isObjectOrFunction) return currentId; - if (currentDepth >= maxDepth) return currentId; + if (!isObjectOrFunction) return currentId; + if (currentDepth >= maxDepth) return currentId; - let properties = []; - try { - properties = Object.getOwnPropertyNames(currentObj); - } catch (e) { - return currentId; - } + let properties = []; + try { + properties = Object.getOwnPropertyNames(currentObj); + } catch (e) { + return currentId; + } - for (const prop of properties) { - let isGetter = typeof(Object.getOwnPropertyDescriptor(currentObj, prop).get) === 'function'; - let value; - try { - value = currentObj[prop]; - } catch (e) { - const errorId = idCounter++; - flatGraph[errorId] = { type: "error", properties: {} }; - node.properties[prop] = { id: errorId, isGetter }; - continue; + for (const prop of properties) { + let isGetter = typeof(Object.getOwnPropertyDescriptor(currentObj, prop).get) === 'function'; + let value; + try { + value = currentObj[prop]; + } catch (e) { + const errorId = idCounter++; + flatGraph[errorId] = { type: "error", properties: {} }; + node.properties[prop] = { id: errorId, isGetter }; + continue; + } + + node.properties[prop] = { + id: walk(value, currentDepth + 1), + isGetter: isGetter + }; + } + return currentId; } - node.properties[prop] = { - id: walk(value, currentDepth + 1), - isGetter: isGetter - }; - } - return currentId; - } - - walk(globalThis, 0); // Start traversal. - const flatJSONData = JSON.stringify(flatGraph, null, 2); - console.log(flatJSONData); -})(); -""" + walk(globalThis, 0); // Start traversal. + const flatJSONData = JSON.stringify(flatGraph, null, 2); + console.log(flatJSONData); + })(); + """ let result = try runner.executeScript(jsProg, withTimeout: 10) guard result.isSuccess else { fatalError("Execution failed: \(result.error)\n\(result.output)") } -let jsEnvironment = JavaScriptEnvironment(additionalBuiltins: profile.additionalBuiltins, additionalObjectGroups: profile.additionalObjectGroups, additionalEnumerations: profile.additionalEnumerations) +let jsEnvironment = JavaScriptEnvironment( + additionalBuiltins: profile.additionalBuiltins, + additionalObjectGroups: profile.additionalObjectGroups, + additionalEnumerations: profile.additionalEnumerations) let jsonString = result.output struct PropertyReference: Codable { @@ -165,12 +171,12 @@ func checkNode(_ nodeId: Int, path: [String]) { } let propertyData = node.properties.filter { - // Each function has a name and a length property. We don't really care about them, so filter - // them out. - (($0.key != "name" && $0.key != "length") || node.type != "function") - // These conversion functions exist on a large amount of objects. The interesting part is - // calling them during type coercion which will happen automatically. - && $0.key != "valueOf" && $0.key != "toString" + // Each function has a name and a length property. We don't really care about them, so filter + // them out. + (($0.key != "name" && $0.key != "length") || node.type != "function") + // These conversion functions exist on a large amount of objects. The interesting part is + // calling them during type coercion which will happen automatically. + && $0.key != "valueOf" && $0.key != "toString" } for (prop, propertyRef) in propertyData { let (childId, isGetter) = (propertyRef.id, propertyRef.isGetter) @@ -186,9 +192,10 @@ func checkNode(_ nodeId: Int, path: [String]) { newPath.append(prop) // Skip paths that are considered uninteresting (e.g. test-only builtins). let pathString = newPath.joined(separator: ".") - let isExcluded = exclusionList[profileName]?.contains { - pathString == $0 || pathString.starts(with: "\($0).") - } ?? false + let isExcluded = + exclusionList[profileName]?.contains { + pathString == $0 || pathString.starts(with: "\($0).") + } ?? false if isExcluded { continue } diff --git a/Sources/REPRLRun/main.swift b/Sources/REPRLRun/main.swift index 41fa352f6..a80b0d2a4 100644 --- a/Sources/REPRLRun/main.swift +++ b/Sources/REPRLRun/main.swift @@ -29,7 +29,6 @@ if CommandLine.arguments.count < 2 { exit(0) } - let ctx = libreprl.reprl_create_context() if ctx == nil { print("Failed to create REPRL context??") @@ -38,7 +37,8 @@ if ctx == nil { let argv = convertToCArray(Array(CommandLine.arguments[1...])) let envp = convertToCArray([]) -if reprl_initialize_context(ctx, argv, envp, /* capture_stdout: */ 1, /* capture stderr: */ 1) != 0 { +if reprl_initialize_context(ctx, argv, envp, /* capture_stdout: */ 1, /* capture stderr: */ 1) != 0 +{ print("Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(ctx)))") } @@ -89,7 +89,9 @@ func runREPRLTests() { if numFailures == 0 { print("All tests passed!") } else { - print("Not all tests passed. That means REPRL support likely isn't properly implemented in the target engine") + print( + "Not all tests passed. That means REPRL support likely isn't properly implemented in the target engine" + ) } } @@ -113,11 +115,15 @@ while true { let (status, exec_time) = execute(code) if status < 0 { - print("Error during script execution: \(String(cString: reprl_get_last_error(ctx))). REPRL support in the target probably isn't working correctly...") + print( + "Error during script execution: \(String(cString: reprl_get_last_error(ctx))). REPRL support in the target probably isn't working correctly..." + ) continue } - print("Execution finished with status \(status) (signaled: \(RIFSIGNALED(status) != 0), timed out: \(RIFTIMEDOUT(status) != 0)) and took \(exec_time / 1000)ms") + print( + "Execution finished with status \(status) (signaled: \(RIFSIGNALED(status) != 0), timed out: \(RIFTIMEDOUT(status) != 0)) and took \(exec_time / 1000)ms" + ) print("========== Fuzzout ==========\n\(String(cString: reprl_fetch_fuzzout(ctx)))") print("========== Stdout ==========\n\(String(cString: reprl_fetch_stdout(ctx)))") print("========== Stderr ==========\n\(String(cString: reprl_fetch_stderr(ctx)))") diff --git a/Sources/RelateTool/main.swift b/Sources/RelateTool/main.swift index 33a9e718a..2bf9dca17 100644 --- a/Sources/RelateTool/main.swift +++ b/Sources/RelateTool/main.swift @@ -35,14 +35,14 @@ public struct V8DifferentialConfig { "--jit-fuzzing", "--maglev-dumping", "--turbofan-dumping", - "--turbofan-dumping-print-deopt-frames" + "--turbofan-dumping-print-deopt-frames", ] public static let referenceArgs: [String] = [ "--no-turbofan", "--no-maglev", "--sparkplug-dumping", - "--interpreter-dumping" + "--interpreter-dumping", ] } @@ -102,7 +102,8 @@ struct Relater { let args = Arguments.parse(from: CommandLine.arguments) guard let jsShellPath = args["--d8"], - let pocPath = args["--poc"] else { + let pocPath = args["--poc"] +else { print("Usage: --d8 --poc [--dump ]") exit(1) } diff --git a/Tests/FuzzilliTests/AnalyzerTest.swift b/Tests/FuzzilliTests/AnalyzerTest.swift index 546e99cd7..a8e60c9e5 100644 --- a/Tests/FuzzilliTests/AnalyzerTest.swift +++ b/Tests/FuzzilliTests/AnalyzerTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class AnalyzerTests: XCTestCase { @@ -105,7 +106,8 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction]) b.await(v3) b.buildAsyncGeneratorFunction(with: .parameters(n: 2)) { _ in - XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction, .generatorFunction]) + XCTAssertEqual( + b.context, [.javascript, .subroutine, .asyncFunction, .generatorFunction]) } XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction]) } @@ -139,12 +141,14 @@ class AnalyzerTests: XCTestCase { let b = fuzzer.makeBuilder() XCTAssertEqual(b.context, .javascript) - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod]) - b.buildDoWhileLoop(do: { - XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod, .loop]) - }, while: { b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + XCTAssertEqual( + b.context, [.javascript, .subroutine, .method, .classMethod, .loop]) + }, while: { b.loadBool(false) }) XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod]) } } @@ -201,12 +205,12 @@ class AnalyzerTests: XCTestCase { let b = fuzzer.makeBuilder() XCTAssertEqual(b.context, .javascript) - let _ = b.buildCodeString() { + let _ = b.buildCodeString { XCTAssertEqual(b.context, .javascript) b.buildRepeatLoop(n: 10) { _ in b.loadInt(1337) XCTAssertEqual(b.context, [.javascript, .loop]) - let _ = b.buildCodeString() { + let _ = b.buildCodeString { b.loadString("hello world") XCTAssertEqual(b.context, [.javascript]) } @@ -226,11 +230,14 @@ class AnalyzerTests: XCTestCase { let _ = b.buildPlainFunction(with: .parameters(n: 5)) { args in XCTAssertEqual(b.context, [.javascript, .subroutine]) - b.buildIfElse(args[0], ifBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, elseBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) + b.buildIfElse( + args[0], + ifBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + elseBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }) b.buildWhileLoop({ XCTAssertEqual(b.context, [.javascript, .subroutine]) @@ -239,21 +246,27 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } - b.buildDoWhileLoop(do: { - XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) - }, while: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - return b.loadBool(false) - }) + b.buildDoWhileLoop( + do: { + XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) + }, + while: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + return b.loadBool(false) + }) - b.buildForLoop({ - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - return b.loadBool(false) - }, { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) { + b.buildForLoop( + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + return b.loadBool(false) + }, + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + } + ) { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } @@ -288,13 +301,16 @@ class AnalyzerTests: XCTestCase { } } - b.buildTryCatchFinally(tryBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, catchBody: { _ in - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, finallyBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) + b.buildTryCatchFinally( + tryBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + catchBody: { _ in + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + finallyBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }) b.blockStatement { XCTAssertEqual(b.context, [.javascript, .subroutine]) @@ -302,10 +318,10 @@ class AnalyzerTests: XCTestCase { } XCTAssertEqual(b.context, .javascript) - let _ = b.finalize() + let _ = b.finalize() } - // Tests if the context is correctly identified in nested loops and switches. + // Tests if the context is correctly identified in nested loops and switches. // Needs to work to distinguish when to emit LoopBreak and SwitchBreak. func testBreakContext() { let fuzzer = makeMockFuzzer() @@ -313,13 +329,13 @@ class AnalyzerTests: XCTestCase { let case1 = b.loadInt(1337) let case2 = b.loadInt(9001) - + // Test case 1: switch -> loop -> switch b.buildSwitch(on: case1) { outer_switch in XCTAssertEqual(b.context, .switchBlock) outer_switch.addCase(case1) { XCTAssertEqual(b.context, [.javascript, .switchCase]) - b.buildWhileLoop({ b.loadBool(true) }) { + b.buildWhileLoop({ b.loadBool(true) }) { XCTAssertEqual(b.context, [.javascript, .loop]) b.buildSwitch(on: case2) { inner_switch in XCTAssertEqual(b.context, .switchBlock) @@ -327,7 +343,7 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .switchCase]) } } - } + } } } XCTAssertEqual(b.context, .javascript) @@ -346,7 +362,7 @@ class AnalyzerTests: XCTestCase { } } XCTAssertEqual(b.context, .javascript) - + let _ = b.finalize() } } diff --git a/Tests/FuzzilliTests/CompilerTests.swift b/Tests/FuzzilliTests/CompilerTests.swift index c27269dc6..5e4230683 100644 --- a/Tests/FuzzilliTests/CompilerTests.swift +++ b/Tests/FuzzilliTests/CompilerTests.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest import Foundation +import XCTest + @testable import Fuzzilli /// Compiler testsuite. @@ -27,14 +28,21 @@ import Foundation /// - The test passes if there are no errors along the way and if the output of both executions is identical class CompilerTests: XCTestCase { func testFuzzILCompiler() throws { - guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { - throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + throw XCTSkip( + "Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } // Initialize the parser. This can fail if no node.js executable is found or if the // parser's node.js dependencies are not installed. In that case, skip these tests. guard let parser = JavaScriptParser(executor: nodejs) else { - throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + throw XCTSkip( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } let compiler = JavaScriptCompiler() @@ -65,13 +73,17 @@ class CompilerTests: XCTestCase { let script = lifter.lift(program) let result2 = try nodejs.executeScript(script) guard result2.isSuccess else { - XCTFail("TestCase \(testName) failed to execute after compiling and lifting. Output:\n\(result2.output)\nScript:\n\(script)") + XCTFail( + "TestCase \(testName) failed to execute after compiling and lifting. Output:\n\(result2.output)\nScript:\n\(script)" + ) continue } // The output of both executions must be identical. if result1.output != result2.output { - XCTFail("Testcase \(testName) failed.\nExpected output:\n\(result1.output)\nActual output:\n\(result2.output)") + XCTFail( + "Testcase \(testName) failed.\nExpected output:\n\(result1.output)\nActual output:\n\(result2.output)" + ) } } } diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index fb068f34f..f2b981fa1 100644 --- a/Tests/FuzzilliTests/ContextGraphTest.swift +++ b/Tests/FuzzilliTests/ContextGraphTest.swift @@ -13,12 +13,14 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ContextGraphTests: XCTestCase { func testReachabilityCalculation() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .javascript)) @@ -33,19 +35,24 @@ class ContextGraphTests: XCTestCase { func testSubsetReachabilityCalculation() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) let reachableContextsWasm = Set(contextGraph.getReachableContexts(from: .wasm)) let reachableContextsWasm2 = Set(contextGraph.getReachableContexts(from: .wasm)) XCTAssertEqual(reachableContextsWasm, reachableContextsWasm2) - let reachableContextsWasmFunction = Set(contextGraph.getReachableContexts(from: .wasmFunction)) + let reachableContextsWasmFunction = Set( + contextGraph.getReachableContexts(from: .wasmFunction)) let reachableContextsJavaScript = Set(contextGraph.getReachableContexts(from: .javascript)) XCTAssertTrue(reachableContextsWasmFunction.isSubset(of: reachableContextsWasm)) - XCTAssertEqual(reachableContextsWasm, - Set([.wasmFunction, - .wasm])) + XCTAssertEqual( + reachableContextsWasm, + Set([ + .wasmFunction, + .wasm, + ])) XCTAssertTrue(reachableContextsWasm.isSubset(of: reachableContextsJavaScript)) } } diff --git a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift index 5863b6c18..fe8149e8c 100644 --- a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift +++ b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift @@ -13,6 +13,7 @@ // limitations under the License. import Foundation + @testable import Fuzzilli // This mutator generates a crashing instrumented program. @@ -30,7 +31,7 @@ class CrashingInstrumentationMutator: RuntimeAssistedMutator { override func instrument(_ program: Program, for fuzzer: Fuzzer) -> Program? { let b = fuzzer.makeBuilder() - b.eval("fuzzilli('FUZZILLI_CRASH', 0)"); + b.eval("fuzzilli('FUZZILLI_CRASH', 0)") // Add a JsInternalOperation to satisfy the assertion in RuntimeAssistedMutator.swift:89 let v = b.loadInt(42) @@ -40,8 +41,10 @@ class CrashingInstrumentationMutator: RuntimeAssistedMutator { return b.finalize() } - - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { // Purpose of this print: Distinguish crashes originating from instrument() and process(). let printFct = b.createNamedVariable(forBuiltin: "print") b.callFunction(printFct, withArgs: [b.loadString("This is the processed program")]) diff --git a/Tests/FuzzilliTests/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift index 00d0e52c9..229588f72 100644 --- a/Tests/FuzzilliTests/DiffOracleTests.swift +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -13,22 +13,23 @@ // limitations under the License. import XCTest + @testable import Fuzzilli final class DiffOracleTests: XCTestCase { func testSimpleIdentity() { let dump = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 - - """ + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 + + """ // Should match itself XCTAssertTrue(DiffOracle.relate(dump, with: dump)) } @@ -37,68 +38,67 @@ final class DiffOracleTests: XCTestCase { // This tests if the second frame correctly inherits 'f:1', 'n:1', 'm:1' from the first frame // and only updates 'b' and 'x'. let unopt = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 - ---I - b:20 - x:200 + ---I + b:20 + x:200 - """ + """ // Even if we explicitly write out the full state in the "Opt" input, // it should match the incremental "Unopt" input if parsing works correctly. let optFull = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 - - ---I - b:20 - f:1 - x:200 - n:1 - m:1 - a0:10 - r0:20 - - """ + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 + + ---I + b:20 + f:1 + x:200 + n:1 + m:1 + a0:10 + r0:20 + + """ XCTAssertTrue(DiffOracle.relate(optFull, with: unopt)) } - func testOptimizedOutAccumulator() { let unopt = """ - ---I - b:10 - f:1 - x:SecretValue - n:0 - m:0 + ---I + b:10 + f:1 + x:SecretValue + n:0 + m:0 - """ + """ let opt = """ - ---I - b:10 - f:1 - x: - n:0 - m:0 + ---I + b:10 + f:1 + x: + n:0 + m:0 - """ + """ // in Opt should match distinct value in Unopt XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) @@ -106,145 +106,144 @@ final class DiffOracleTests: XCTestCase { func testOptimizedOutArgument() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0:RealVal - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0:RealVal + a1:OtherVal - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0: - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0: + a1:OtherVal - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } func testNonMaterializedArgument() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0:RealVal - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0:RealVal + a1:OtherVal - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0: - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0: + a1:OtherVal - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } func testArgumentMismatch() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:1 - m:0 - a0:ValueA + ---I + b:10 + f:1 + x:0 + n:1 + m:0 + a0:ValueA - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:1 - m:0 - a0:ValueB + ---I + b:10 + f:1 + x:0 + n:1 + m:0 + a0:ValueB - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } func testRegisterMismatch() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:0 - m:1 - r0:ValueA + ---I + b:10 + f:1 + x:0 + n:0 + m:1 + r0:ValueA - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:0 - m:1 - r0:ValueB + ---I + b:10 + f:1 + x:0 + n:0 + m:1 + r0:ValueB - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } - func testSkipsUnoptimizedFrames() { // Scenario: Unoptimized dump has extra intermediate steps (frames at offset 20 and 30). // Optimized dump only snapshots offset 10 and 40. This is valid. let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:20 + ---I + b:20 - ---I - b:30 + ---I + b:30 - ---I - b:40 + ---I + b:40 - """ + """ let opt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:40 + ---I + b:40 - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } @@ -253,50 +252,50 @@ final class DiffOracleTests: XCTestCase { // Scenario: Opt dump tries to match b:40 BEFORE b:10. This is invalid. // The relatation consumes the unopt stream forward. let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:40 + ---I + b:40 - """ + """ let opt = """ - ---I - b:40 - f:1 - n:0 - m:0 + ---I + b:40 + f:1 + n:0 + m:0 - ---I - b:10 + ---I + b:10 - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } func testBytecodeOffsetMismatch() { let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - """ + """ let opt = """ - ---I - b:99 - f:1 - n:0 - m:0 + ---I + b:99 + f:1 + n:0 + m:0 - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } @@ -306,36 +305,36 @@ final class DiffOracleTests: XCTestCase { // when n counts change between frames. let unopt = """ - ---I - b:10 - f:1 - n:1 - m:0 - a0:A + ---I + b:10 + f:1 + n:1 + m:0 + a0:A - ---I - b:20 - n:2 - a1:B + ---I + b:20 + n:2 + a1:B - """ + """ // This opt dump expects a0 to still be A (carried over) and a1 to be B. let opt = """ - ---M - b:10 - f:1 - n:1 - m:0 - a0:A + ---M + b:10 + f:1 + n:1 + m:0 + a0:A - ---M - b:20 - n:2 - a0:A - a1:B + ---M + b:20 + n:2 + a0:A + a1:B - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } @@ -347,36 +346,36 @@ final class DiffOracleTests: XCTestCase { // 3. Go back to having two registers (m:2) in the third frame. r1 should still be B (inherited from frame 0). let trace = """ - ---I - b:10 - f:1 - n:0 - m:2 - r0:A - r1:B - - ---M - b:20 - m:1 - r0:A_Prime - - ---I - b:30 - m:2 - r0:A_Prime - - """ + ---I + b:10 + f:1 + n:0 + m:2 + r0:A + r1:B + + ---M + b:20 + m:1 + r0:A_Prime + + ---I + b:30 + m:2 + r0:A_Prime + + """ let expectedLastFrame = """ - ---I - b:30 - f:1 - n:0 - m:2 - r0:A_Prime - r1:B - - """ + ---I + b:30 + f:1 + n:0 + m:2 + r0:A_Prime + r1:B + + """ XCTAssertTrue(DiffOracle.relate(expectedLastFrame, with: trace)) } @@ -386,31 +385,31 @@ final class DiffOracleTests: XCTestCase { // Frame 2: m=3. The parser must grow the buffer. r1 and r2 should be "". let trace = """ - ---I - b:10 - f:1 - n:0 - m:1 - r0:A + ---I + b:10 + f:1 + n:0 + m:1 + r0:A - ---I - b:20 - m:3 + ---I + b:20 + m:3 - """ + """ // Explicitly check that r1 and r2 are missing in the expanded frame. let explicitMissing = """ - ---I - b:20 - f:1 - n:0 - m:3 - r0:A - r1: - r2: + ---I + b:20 + f:1 + n:0 + m:3 + r0:A + r1: + r2: - """ + """ XCTAssertTrue(DiffOracle.relate(explicitMissing, with: trace)) } @@ -420,62 +419,64 @@ final class DiffOracleTests: XCTestCase { // Buffer should auto-grow and fill with . let trace = """ - ---I - b:10 - f:1 - n:0 - m:10 - r9:Z + ---I + b:10 + f:1 + n:0 + m:10 + r9:Z - """ + """ // This frame should have r0...r8 as and r9 as Z. let expected = """ - ---I - b:10 - f:1 - n:0 - m:10 - r0: - r1: - r2: - r3: - r4: - r5: - r6: - r6: - r7: - r8: - r9:Z - - """ + ---I + b:10 + f:1 + n:0 + m:10 + r0: + r1: + r2: + r3: + r4: + r5: + r6: + r6: + r7: + r8: + r9:Z + + """ XCTAssertTrue(DiffOracle.relate(expected, with: trace)) } func testEmptyStringValueParsing() { let unopt = """ - ---I - b:10 - f:1 - n:0 - m:6 - r0:ValA - r5: + ---I + b:10 + f:1 + n:0 + m:6 + r0:ValA + r5: - """ + """ let opt = """ - ---I - b:10 - f:1 - n:0 - m:6 - r0:ValA - r5: - - """ - - XCTAssertTrue(DiffOracle.relate(opt, with: unopt), "Should handle empty register values (e.g. 'r5:') without crashing") + ---I + b:10 + f:1 + n:0 + m:6 + r0:ValA + r5: + + """ + + XCTAssertTrue( + DiffOracle.relate(opt, with: unopt), + "Should handle empty register values (e.g. 'r5:') without crashing") } } diff --git a/Tests/FuzzilliTests/EngineTests.swift b/Tests/FuzzilliTests/EngineTests.swift index 6d0960a48..e6f1e0cf7 100644 --- a/Tests/FuzzilliTests/EngineTests.swift +++ b/Tests/FuzzilliTests/EngineTests.swift @@ -13,11 +13,12 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class EngineTests: XCTestCase { func testPostProcessorOnGenerativeEngine() throws { - class MockPostProcessor : FuzzingPostProcessor { + class MockPostProcessor: FuzzingPostProcessor { var callCount = 0 func process(_ program: Program, for fuzzer: Fuzzer) -> Program { callCount += 1 @@ -55,7 +56,7 @@ class EngineTests: XCTestCase { let fuzzer = makeMockFuzzer() let processor = DumplingFuzzingPostProcessor() - let rejectedCases: [(ProgramBuilder) -> ()] = [ + let rejectedCases: [(ProgramBuilder) -> Void] = [ { b in let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } b.getProperty("arguments", of: f) @@ -88,7 +89,7 @@ class EngineTests: XCTestCase { XCTAssertThrowsError(try processor.process(program, for: fuzzer), "test case \(i)") } - for acceptedCase: (ProgramBuilder) -> () in [ + for acceptedCase: (ProgramBuilder) -> Void in [ { b in let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } b.getProperty("not_arguments", of: f) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index 7819fa883..adb3e8456 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class EnvironmentTests: XCTestCase { @@ -25,19 +26,21 @@ class EnvironmentTests: XCTestCase { /// Test all the builtin objects that are reachable from the global this. /// (This does not include anything that needs a constructor to be called.) func testJSEnvironmentLive() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) let jsProg = buildAndLiftProgram(withLiftingOptions: [.includeComments]) { b in let jsEnvironment = b.fuzzer.environment var seenTypeGroups = Set() var propertiesToCheck: [(Variable, String, String)] = [] - let enqueueProperties = {(builtin: Variable, path: String, type: ILType) in + let enqueueProperties = { (builtin: Variable, path: String, type: ILType) in if type.group == nil || seenTypeGroups.insert(type.group!).inserted { - propertiesToCheck.append(contentsOf: - type.properties.sorted().map {(builtin, $0, "\(path).\($0)")} + - type.methods.sorted().map {(builtin, $0, "\(path).\($0)")}) + propertiesToCheck.append( + contentsOf: + type.properties.sorted().map { (builtin, $0, "\(path).\($0)") } + + type.methods.sorted().map { (builtin, $0, "\(path).\($0)") }) } } - let handleBuiltin = {builtin, path in + let handleBuiltin = { builtin, path in // Do something with the builtin to check that it exists (even if it might not have any // registered properties or methods). // The .LogicOr is only done for error reporting, e.g.: @@ -50,7 +53,7 @@ class EnvironmentTests: XCTestCase { if type.Is(.constructor()), let signature = type.constructorSignature { // If the object is default-constructible, instantiate it. // Otherwise we can't know how to construct a valid instance. - if (signature.parameters.allSatisfy {$0.isOptionalParameter}) { + if (signature.parameters.allSatisfy { $0.isOptionalParameter }) { let instance = b.construct(builtin) enqueueProperties(instance, "(new \(path)())", b.type(of: instance)) } @@ -59,7 +62,7 @@ class EnvironmentTests: XCTestCase { for builtinName in jsEnvironment.builtins.sorted() where builtinName != "undefined" { handleBuiltin(b.createNamedVariable(forBuiltin: builtinName), builtinName) } - let blockList : Set = ["arguments", "caller"] + let blockList: Set = ["arguments", "caller"] while let (builtinVar, name, path) = propertiesToCheck.popLast() { if blockList.contains(name) { continue } let builtin = b.getProperty(name, of: builtinVar) @@ -76,24 +79,28 @@ class EnvironmentTests: XCTestCase { func convertTypedArrayToHex(_ b: ProgramBuilder, _ array: Variable) -> Variable { let toHex = b.buildArrowFunction(with: .parameters(n: 1)) { args in let hex = b.callMethod("toString", on: args[0], withArgs: [b.loadInt(16)]) - let hexPadded = b.callMethod("padStart", on: hex, withArgs: [b.loadInt(2), b.loadString("0")]) + let hexPadded = b.callMethod( + "padStart", on: hex, withArgs: [b.loadInt(2), b.loadString("0")]) b.doReturn(hexPadded) } - let untypedArray = b.construct(b.createNamedVariable(forBuiltin: "Array"), + let untypedArray = b.construct( + b.createNamedVariable(forBuiltin: "Array"), withArgs: [array], spreading: [true]) let hexArray = b.callMethod("map", on: untypedArray, withArgs: [toHex]) return b.callMethod("join", on: hexArray, withArgs: [b.loadString("")]) } func testBase64OptionsBag() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--js-base-64"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--js-base-64"]) let jsProg = buildAndLiftProgram { b in let arrayConstructor = b.createNamedVariable(forBuiltin: "Uint8Array") // Whatever the options object looks like, it should construct something valid. // With the provided input string, the actual options should not matter. let options = b.createOptionsBag(OptionsBag.fromBase64Settings) let inputString = b.loadString("qxI0VniQq83v") - let array = b.callMethod("fromBase64", on: arrayConstructor, withArgs: [inputString, options]) + let array = b.callMethod( + "fromBase64", on: arrayConstructor, withArgs: [inputString, options]) XCTAssert(b.type(of: array).Is(.object(ofGroup: "Uint8Array"))) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [convertTypedArrayToHex(b, array)]) @@ -103,7 +110,8 @@ class EnvironmentTests: XCTestCase { b.callMethod("setFromBase64", on: array, withArgs: [inputString2, options2]) b.callFunction(outputFunc, withArgs: [convertTypedArrayToHex(b, array)]) } - testForOutput(program: jsProg, runner: runner, + testForOutput( + program: jsProg, runner: runner, outputString: "ab1234567890abcdef\nbaaddeadbeefabcdef\n") } } diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 20f549f2b..e41776ea4 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class JSTyperTests: XCTestCase { @@ -46,28 +47,37 @@ class JSTyperTests: XCTestCase { obj.addMethod("m", with: .parameters(.integer)) { args in let this = args[0] // Up to this point, only the "a" property has been installed - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) XCTAssertEqual(b.type(of: args[1]), .integer) let notArg = b.unary(.LogicalNot, args[1]) b.doReturn(notArg) } obj.addGetter(for: "b") { this in // We don't add the "b" property to the |this| type here since it's probably not very useful to access it inside its getter/setter. - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"], withMethods: ["m"])) } obj.addSetter(for: "c") { this, v in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Object0", withProperties: ["a", "b"], withMethods: ["m"])) } } - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b", "c"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b", "c"], withMethods: ["m"])) let obj2 = b.buildObjectLiteral { obj in obj.addProperty("prop", as: v) obj.addElement(0, as: v) } - XCTAssertEqual(b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["prop"])) + XCTAssertEqual( + b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["prop"])) } func testNestedObjectLiterals() { @@ -79,19 +89,25 @@ class JSTyperTests: XCTestCase { outer.addProperty("a", as: v) outer.addMethod("m", with: .parameters(n: 1)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) b.buildObjectLiteral { inner in inner.addProperty("b", as: v) inner.addMethod("n", with: .parameters(n: 0)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object1", withProperties: ["b"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Object1", withProperties: ["b"])) } } } outer.addProperty("c", as: v) outer.addMethod("o", with: .parameters(n: 0)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "c"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Object0", withProperties: ["a", "c"], withMethods: ["m"])) } } } @@ -105,19 +121,25 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: obj, to: intVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) b.setProperty("baz", of: obj, to: intVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) let _ = b.deleteProperty("foo", of: obj) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["bar", "baz"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["bar", "baz"])) // Properties whose values are functions are still treated as properties, not methods. let function = b.buildPlainFunction(with: .parameters(n: 1)) { params in } XCTAssertEqual(b.type(of: function), .functionAndConstructor([.jsAnything] => .undefined)) let obj2 = b.createObject(with: ["foo": intVar, "bar": intVar, "baz": function]) - XCTAssertEqual(b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: obj2), + .object(ofGroup: "_fuzz_Object1", withProperties: ["foo", "bar", "baz"])) } func testClasses() { @@ -125,7 +147,7 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let v = b.loadInt(42) - let cls = b.buildClassDefinition() { cls in + let cls = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.string])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -140,7 +162,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) XCTAssertEqual(b.type(of: params[1]), .float) XCTAssertEqual(b.type(of: v), .integer | .string) b.reassign(variable: v, value: params[1]) @@ -148,12 +171,19 @@ class JSTyperTests: XCTestCase { } cls.addInstanceGetter(for: "c") { this in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b"], withMethods: ["f"])) } cls.addInstanceMethod("g", with: .parameters(n: 2)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f"] + )) XCTAssertEqual(b.type(of: params[1]), .jsAnything) XCTAssertEqual(b.type(of: params[2]), .jsAnything) } @@ -163,34 +193,61 @@ class JSTyperTests: XCTestCase { cls.addStaticMethod("g", with: .parameters(n: 2)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"])) XCTAssertEqual(b.type(of: params[1]), .jsAnything) XCTAssertEqual(b.type(of: params[2]), .jsAnything) } cls.addStaticSetter(for: "e") { this, v in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"], withMethods: ["g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"], + withMethods: ["g"])) } cls.addStaticMethod("h", with: .parameters(.integer)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g"])) XCTAssertEqual(b.type(of: params[1]), .integer) } cls.addPrivateInstanceMethod("p", with: .parameters(n: 0)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f", "g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], + withMethods: ["f", "g"])) } cls.addPrivateStaticMethod("p", with: .parameters(n: 0)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g", "h"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g", "h"])) } } XCTAssertEqual(b.type(of: v), .integer | .string | .float) - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g", "h"]) + .constructor([.string] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g", "h"]) + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], + withMethods: ["f", "g"]))) } func testClasses2() { @@ -200,7 +257,7 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) let s = b.loadString("foo") let f = b.loadFloat(13.37) - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in // Class methods, getters, setters, etc. are treated as conditionally executing blocks. cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in XCTAssertEqual(b.type(of: v), .integer) @@ -247,35 +304,49 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .primitive | .object() | .iterable) XCTAssertEqual(b.type(of: s), .jsString | .float) - XCTAssertEqual(b.type(of: f), .boolean) // A static initializer block runs unconditionally + XCTAssertEqual(b.type(of: f), .boolean) // A static initializer block runs unconditionally } func testNestedClasses() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let outer = b.buildClassDefinition() { cls in + let outer = b.buildClassDefinition { cls in cls.addInstanceProperty("a") cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in let inner = b.buildClassDefinition { cls in cls.addInstanceProperty("a") cls.addInstanceProperty("b") } - XCTAssertEqual(b.type(of: inner), .object(ofGroup: "_fuzz_Constructor1") + .constructor([] => .object(ofGroup: "_fuzz_Class1", withProperties: ["a", "b"]))) + XCTAssertEqual( + b.type(of: inner), + .object(ofGroup: "_fuzz_Constructor1") + + .constructor( + [] => .object(ofGroup: "_fuzz_Class1", withProperties: ["a", "b"]))) } cls.addInstanceProperty("c") } - XCTAssertEqual(b.type(of: outer), .object(ofGroup: "_fuzz_Constructor0") + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "c"], withMethods: ["m"]))) + XCTAssertEqual( + b.type(of: outer), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "c"], withMethods: ["m"]) + )) } func testSubClasses() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let base1 = b.buildClassDefinition() { cls in + let base1 = b.buildClassDefinition { cls in cls.addInstanceProperty("a") } - XCTAssertEqual(b.type(of: base1), .object(ofGroup: "_fuzz_Constructor0") + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) + XCTAssertEqual( + b.type(of: base1), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) let v = b.loadInt(42) let base2 = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -284,7 +355,9 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - XCTAssertEqual(b.type(of: base2), .functionAndConstructor([] => .object(ofGroup: "_fuzz_Object2", withProperties: ["b"]))) + XCTAssertEqual( + b.type(of: base2), + .functionAndConstructor([] => .object(ofGroup: "_fuzz_Object2", withProperties: ["b"]))) let base3 = b.buildPlainFunction(with: .parameters(n: 0)) { _ in b.doReturn(v) @@ -297,29 +370,45 @@ class JSTyperTests: XCTestCase { let derived1 = b.buildClassDefinition(withSuperclass: base1) { cls in cls.addInstanceProperty("c") } - XCTAssertEqual(b.type(of: derived1), .object(ofGroup: "_fuzz_Constructor3") + .constructor([] => .object(ofGroup: "_fuzz_Class3", withProperties: ["a", "c"]))) + XCTAssertEqual( + b.type(of: derived1), + .object(ofGroup: "_fuzz_Constructor3") + + .constructor([] => .object(ofGroup: "_fuzz_Class3", withProperties: ["a", "c"]))) let derived2 = b.buildClassDefinition(withSuperclass: base2) { cls in cls.addInstanceProperty("d") } - XCTAssertEqual(b.type(of: derived2), .object(ofGroup: "_fuzz_Constructor5") + .constructor([] => .object(ofGroup: "_fuzz_Class5", withProperties: ["b", "d"]))) + XCTAssertEqual( + b.type(of: derived2), + .object(ofGroup: "_fuzz_Constructor5") + + .constructor([] => .object(ofGroup: "_fuzz_Class5", withProperties: ["b", "d"]))) // base3 does not return an object, so that return type is ignored for the constructor. // TODO: Technically, base3 used as a constructor would return |this|, so we'd have to use the type of |this| if the returned value is not an object in our type inference, but we don't currently do that. let derived3 = b.buildClassDefinition(withSuperclass: base3) { cls in cls.addInstanceProperty("e") } - XCTAssertEqual(b.type(of: derived3), .object(ofGroup: "_fuzz_Constructor7") + .constructor([] => .object(ofGroup: "_fuzz_Class7", withProperties: ["e"]))) + XCTAssertEqual( + b.type(of: derived3), + .object(ofGroup: "_fuzz_Constructor7") + + .constructor([] => .object(ofGroup: "_fuzz_Class7", withProperties: ["e"]))) let derived4 = b.buildClassDefinition(withSuperclass: base4) { cls in cls.addInstanceProperty("f") } - XCTAssertEqual(b.type(of: derived4), .object(ofGroup: "_fuzz_Constructor9") + .constructor([] => .object(ofGroup: "_fuzz_Class9", withProperties: ["f"]))) + XCTAssertEqual( + b.type(of: derived4), + .object(ofGroup: "_fuzz_Constructor9") + + .constructor([] => .object(ofGroup: "_fuzz_Class9", withProperties: ["f"]))) let derived5 = b.buildClassDefinition(withSuperclass: derived1) { cls in cls.addInstanceProperty("g") } - XCTAssertEqual(b.type(of: derived5), .object(ofGroup: "_fuzz_Constructor11") + .constructor([] => .object(ofGroup: "_fuzz_Class11", withProperties: ["a", "c", "g"]))) + XCTAssertEqual( + b.type(of: derived5), + .object(ofGroup: "_fuzz_Constructor11") + + .constructor( + [] => .object(ofGroup: "_fuzz_Class11", withProperties: ["a", "c", "g"]))) } func testSubroutineTypes() { @@ -330,35 +419,59 @@ class JSTyperTests: XCTestCase { let signature2 = [.string, .number] => .undefined // Plain functions are both functions and constructors. This might yield interesting results since these function often return a value. - var f = b.buildPlainFunction(with: .parameters(n: 2)) { params in XCTAssertEqual(b.type(of: params[0]), .jsAnything); XCTAssertEqual(b.type(of: params[1]), .jsAnything) } - XCTAssertEqual(b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) + var f = b.buildPlainFunction(with: .parameters(n: 2)) { params in + XCTAssertEqual(b.type(of: params[0]), .jsAnything) + XCTAssertEqual(b.type(of: params[1]), .jsAnything) + } + XCTAssertEqual( + b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) - f = b.buildPlainFunction(with: .parameters(signature1.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildPlainFunction(with: .parameters(signature1.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .functionAndConstructor(signature1)) - f = b.buildPlainFunction(with: .parameters(n: 2)) { params in XCTAssertEqual(b.type(of: params[0]), .jsAnything); XCTAssertEqual(b.type(of: params[1]), .jsAnything) } - XCTAssertEqual(b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) + f = b.buildPlainFunction(with: .parameters(n: 2)) { params in + XCTAssertEqual(b.type(of: params[0]), .jsAnything) + XCTAssertEqual(b.type(of: params[1]), .jsAnything) + } + XCTAssertEqual( + b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) // All other function types are just functions... - f = b.buildArrowFunction(with: .parameters(signature2.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildArrowFunction(with: .parameters(signature2.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature2)) let signature3 = [.integer, .number] => .jsGenerator - f = b.buildGeneratorFunction(with: .parameters(signature3.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildGeneratorFunction(with: .parameters(signature3.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature3)) - f = b.buildAsyncGeneratorFunction(with: .parameters(signature3.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncGeneratorFunction(with: .parameters(signature3.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature3)) let signature4 = [.string, .number] => .jsPromise - f = b.buildAsyncFunction(with: .parameters(signature4.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncFunction(with: .parameters(signature4.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature4)) - f = b.buildAsyncArrowFunction(with: .parameters(signature4.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncArrowFunction(with: .parameters(signature4.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature4)) - - // ... except for constructors, which are just constructors (when they are lifted to JavaScript, they explicitly forbid being called as a function). let signature5 = [.integer, .number] => .object(withProperties: ["foo", "bar"]) f = b.buildConstructor(with: .parameters(signature3.parameters)) { params in @@ -386,42 +499,56 @@ class JSTyperTests: XCTestCase { let o = b.createObject(with: ["a": b.loadInt(42)]) b.doReturn(o) } - XCTAssertEqual(b.type(of: f2).signature?.outputType, .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: f2).signature?.outputType, + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) let f3 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadFloat(13.37)) - }, elseBody: { - b.doReturn(b.loadString("13.37")) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadFloat(13.37)) + }, + elseBody: { + b.doReturn(b.loadString("13.37")) + }) b.doReturn(b.loadBool(false)) } XCTAssertEqual(b.type(of: f3).signature?.outputType, .float | .jsString) let f4 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadString("foo")) - }, elseBody: { - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadString("foo")) + }, + elseBody: { + }) } XCTAssertEqual(b.type(of: f4).signature?.outputType, .undefined | .jsString) let f5 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadString("foo")) - }, elseBody: { - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadString("foo")) + }, + elseBody: { + }) b.doReturn(b.loadBool(true)) } XCTAssertEqual(b.type(of: f5).signature?.outputType, .boolean | .jsString) let f6 = b.buildPlainFunction(with: .parameters(n: 1)) { args in b.doReturn(b.loadInt(42)) - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadFloat(13.37)) - }, elseBody: { - b.doReturn(b.loadString("13.37")) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadFloat(13.37)) + }, + elseBody: { + b.doReturn(b.loadString("13.37")) + }) b.doReturn(b.loadBool(false)) } XCTAssertEqual(b.type(of: f6).signature?.outputType, .integer) @@ -450,11 +577,14 @@ class JSTyperTests: XCTestCase { b.doReturn(b.loadInt(42)) } b.buildIf(args[1]) { - b.buildIfElse(args[2], ifBody: { - b.doReturn(b.loadBool(true)) - }, elseBody: { - b.doReturn(b.loadBool(false)) - }) + b.buildIfElse( + args[2], + ifBody: { + b.doReturn(b.loadBool(true)) + }, + elseBody: { + b.doReturn(b.loadBool(false)) + }) // This is ignored: all paths have already returned b.doReturn(b.loadString("foobar")) } @@ -481,7 +611,9 @@ class JSTyperTests: XCTestCase { let o = b.createObject(with: ["a": args[1], "b": args[2]]) b.doReturn(o) } - XCTAssertEqual(b.type(of: c3).signature?.outputType, .object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"])) + XCTAssertEqual( + b.type(of: c3).signature?.outputType, + .object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"])) let g1 = b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(b.loadInt(42)) @@ -545,29 +677,39 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) let obj = b.createObject(with: ["foo": v]) - b.buildIfElse(v, ifBody: { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) - b.setProperty("bar", of: obj, to: v) - b.setProperty("baz", of: obj, to: v) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) - - XCTAssertEqual(b.type(of: v), .integer) - let stringVar = b.loadString("foobar") - b.reassign(variable: v, value: stringVar) - XCTAssertEqual(b.type(of: v), .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) - b.setProperty("bar", of: obj, to: v) - b.setProperty("bla", of: obj, to: v) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) - - XCTAssertEqual(b.type(of: v), .integer) - let floatVar = b.loadFloat(13.37) - b.reassign(variable: v, value: floatVar) - }) + b.buildIfElse( + v, + ifBody: { + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + b.setProperty("bar", of: obj, to: v) + b.setProperty("baz", of: obj, to: v) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + + XCTAssertEqual(b.type(of: v), .integer) + let stringVar = b.loadString("foobar") + b.reassign(variable: v, value: stringVar) + XCTAssertEqual(b.type(of: v), .jsString) + }, + elseBody: { + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + b.setProperty("bar", of: obj, to: v) + b.setProperty("bla", of: obj, to: v) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) + + XCTAssertEqual(b.type(of: v), .integer) + let floatVar = b.loadFloat(13.37) + b.reassign(variable: v, value: floatVar) + }) XCTAssertEqual(b.type(of: v), .string | .float | .object() | .iterable) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) // Test another program using if/else b.reset() @@ -576,17 +718,19 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(42) XCTAssertEqual(b.type(of: v0), .integer) XCTAssertEqual(b.type(of: v1), .integer) - b.buildIfElse(v0, ifBody: { - b.reassign(variable: v0, value: b.loadString("foo")) - b.reassign(variable: v1, value: b.loadString("foo")) - }, elseBody: { - b.reassign(variable: v1, value: b.loadString("bar")) - }) + b.buildIfElse( + v0, + ifBody: { + b.reassign(variable: v0, value: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) + }, + elseBody: { + b.reassign(variable: v1, value: b.loadString("bar")) + }) XCTAssertEqual(b.type(of: v0), .integer | .jsString) XCTAssertEqual(b.type(of: v1), .jsString) - // Test another program using just if b.reset() @@ -606,27 +750,36 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) XCTAssertEqual(b.type(of: v), .integer) - b.buildIfElse(v, ifBody: { - b.buildIfElse(v, ifBody: { - b.buildIfElse(v, ifBody: { - b.reassign(variable: v, value: b.loadString("foo")) - XCTAssertEqual(b.type(of: v), .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: v), .integer) - b.reassign(variable: v, value: b.loadBool(true)) - XCTAssertEqual(b.type(of: v), .boolean) - }) - - XCTAssertEqual(b.type(of: v), .boolean | .jsString) - }, elseBody: { + b.buildIfElse( + v, + ifBody: { + b.buildIfElse( + v, + ifBody: { + b.buildIfElse( + v, + ifBody: { + b.reassign(variable: v, value: b.loadString("foo")) + XCTAssertEqual(b.type(of: v), .jsString) + }, + elseBody: { + XCTAssertEqual(b.type(of: v), .integer) + b.reassign(variable: v, value: b.loadBool(true)) + XCTAssertEqual(b.type(of: v), .boolean) + }) + + XCTAssertEqual(b.type(of: v), .boolean | .jsString) + }, + elseBody: { + XCTAssertEqual(b.type(of: v), .integer) + }) + + XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) + }, + elseBody: { XCTAssertEqual(b.type(of: v), .integer) }) - XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: v), .integer) - }) - XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) } @@ -658,21 +811,24 @@ class JSTyperTests: XCTestCase { let obj = b.createObject(with: ["foo": v]) func body() { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: obj, to: intVar1) XCTAssertEqual(b.type(of: v), .jsString) let floatVar = b.loadFloat(13.37) b.reassign(variable: v, value: floatVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v), .float) } // Select loop type switch i { case 0: - b.buildForLoop() { + b.buildForLoop { body() } case 1: @@ -706,7 +862,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: intVar2), .integer) XCTAssertEqual(b.type(of: intVar3), .integer) XCTAssertEqual(b.type(of: v), .float | .jsString) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.reset() } @@ -714,13 +871,14 @@ class JSTyperTests: XCTestCase { func testBuiltinTypeInference() { let builtinAType = ILType.integer - let builtinBType = ILType.object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]) + let builtinBType = ILType.object( + ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]) let builtinCType = ILType.function([] => .number) let env = JavaScriptEnvironment(additionalBuiltins: [ "A": builtinAType, "B": builtinBType, - "C": builtinCType + "C": builtinCType, ]) let fuzzer = makeMockFuzzer(environment: env) @@ -740,27 +898,30 @@ class JSTyperTests: XCTestCase { let propBarType = ILType.function([] => .jsAnything) let propBazType = ILType.object(withProperties: ["a", "b", "c"]) let additionalObjectGroups: [ObjectGroup] = [ - ObjectGroup(name: "B", - instanceType: .object(ofGroup: "B", withProperties: ["foo", "bar"]), - properties: [ + ObjectGroup( + name: "B", + instanceType: .object(ofGroup: "B", withProperties: ["foo", "bar"]), + properties: [ "foo": propFooType, - "bar": propBarType - ], + "bar": propBarType, + ], overloads: [:]), - ObjectGroup(name: "C", - instanceType: .object(ofGroup: "C", withProperties: ["baz"]), + ObjectGroup( + name: "C", + instanceType: .object(ofGroup: "C", withProperties: ["baz"]), properties: [ - "baz": propBazType, - ], - overloads: [:]) + "baz": propBazType + ], + overloads: [:]), ] let builtins: [String: ILType] = [ "B": .object(ofGroup: "B"), - "C": .object(ofGroup: "C") + "C": .object(ofGroup: "C"), ] - let env = JavaScriptEnvironment(additionalBuiltins: builtins, additionalObjectGroups: additionalObjectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: builtins, additionalObjectGroups: additionalObjectGroups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() @@ -797,22 +958,25 @@ class JSTyperTests: XCTestCase { let m1Signature = [] => .float let m2Signature = [.string] => .object(ofGroup: "X") let groups: [ObjectGroup] = [ - ObjectGroup(name: "B", - instanceType: .object(ofGroup: "B", withMethods: ["m1"]), - properties: [:], - methods: ["m1": m1Signature]), - ObjectGroup(name: "C", - instanceType: .object(ofGroup: "C", withMethods: ["m2"]), - properties: [:], - methods: ["m2": m2Signature]), + ObjectGroup( + name: "B", + instanceType: .object(ofGroup: "B", withMethods: ["m1"]), + properties: [:], + methods: ["m1": m1Signature]), + ObjectGroup( + name: "C", + instanceType: .object(ofGroup: "C", withMethods: ["m2"]), + properties: [:], + methods: ["m2": m2Signature]), ] let builtins: [String: ILType] = [ "B": .object(ofGroup: "B"), - "C": .object(ofGroup: "C") + "C": .object(ofGroup: "C"), ] - let env = JavaScriptEnvironment(additionalBuiltins: builtins, additionalObjectGroups: groups) + let env = JavaScriptEnvironment( + additionalBuiltins: builtins, additionalObjectGroups: groups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() @@ -836,7 +1000,7 @@ class JSTyperTests: XCTestCase { func testConstructorTypeInference() { let aConstructorType = ILType.constructor([.rest(.jsAnything)] => .object(ofGroup: "A")) let builtins: [String: ILType] = [ - "A": aConstructorType, + "A": aConstructorType ] let env = JavaScriptEnvironment(additionalBuiltins: builtins) @@ -869,7 +1033,7 @@ class JSTyperTests: XCTestCase { func testReturnTypeInference() { let aFunctionType = ILType.function([.rest(.jsAnything)] => .primitive) let builtins: [String: ILType] = [ - "a": aFunctionType, + "a": aFunctionType ] let env = JavaScriptEnvironment(additionalBuiltins: builtins) @@ -904,7 +1068,7 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.integer])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -917,7 +1081,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) XCTAssertEqual(b.currentSuperType(), .object()) XCTAssertEqual(b.type(of: params[1]), .float) @@ -926,17 +1091,30 @@ class JSTyperTests: XCTestCase { } } - let superType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: superclass), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => superType)) + let superType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) + XCTAssertEqual( + b.type(of: superclass), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => superType)) let v = b.loadInt(42) let cls = b.buildClassDefinition(withSuperclass: superclass) { cls in cls.addInstanceProperty("b", value: v) cls.addConstructor(with: .parameters([.string])) { params in - XCTAssertEqual(b.currentSuperConstructorType(), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]))) + XCTAssertEqual( + b.currentSuperConstructorType(), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [.integer] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], + withMethods: ["f"]))) let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) XCTAssertEqual(b.currentSuperType(), superType) b.callSuperConstructor(withArgs: [b.loadFloat(42)]) @@ -944,11 +1122,21 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) XCTAssertEqual(b.currentSuperType(), superType) } } - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor2") + .constructor([.string] => .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object(ofGroup: "_fuzz_Constructor2") + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], + withMethods: ["f", "g"]))) } func testBigintTypeInference() { @@ -958,8 +1146,8 @@ class JSTyperTests: XCTestCase { let i1 = b.loadInt(42) let i2 = b.loadInt(43) XCTAssert(b.type(of: i1).Is(.integer)) - let bi1 = b.loadBigInt(4200000000) - let bi2 = b.loadBigInt(4300000000) + let bi1 = b.loadBigInt(4_200_000_000) + let bi2 = b.loadBigInt(4_300_000_000) XCTAssert(b.type(of: bi1).Is(.bigint)) for op in UnaryOperator.allCases { @@ -989,8 +1177,8 @@ class JSTyperTests: XCTestCase { let i3 = b.loadInt(45) let i4 = b.loadInt(46) XCTAssert(b.type(of: i3).Is(.integer)) - let bi3 = b.loadBigInt(4200000000) - let bi4 = b.loadBigInt(4300000000) + let bi3 = b.loadBigInt(4_200_000_000) + let bi4 = b.loadBigInt(4_300_000_000) XCTAssert(b.type(of: bi3).Is(.bigint)) // Logical operators produce .boolean in any case @@ -1014,7 +1202,10 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // The header executes unconditionally, but the body does not - b.buildWhileLoop({ b.reassign(variable: v1, value: b.loadString("foo")); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.reassign(variable: v1, value: b.loadString("foo")) + return b.loadBool(false) + }) { b.reassign(variable: v2, value: b.loadString("bar")) } @@ -1029,9 +1220,14 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // Both the header and the body execute unconditionally - b.buildDoWhileLoop(do: { - b.reassign(variable: v2, value: b.loadString("foo")) - }, while: { b.reassign(variable: v1, value: b.loadString("bar")); return b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + b.reassign(variable: v2, value: b.loadString("foo")) + }, + while: { + b.reassign(variable: v1, value: b.loadString("bar")) + return b.loadBool(false) + }) XCTAssertEqual(b.type(of: v1), .jsString) XCTAssertEqual(b.type(of: v2), .jsString) @@ -1047,14 +1243,18 @@ class JSTyperTests: XCTestCase { let v4 = b.loadInt(3) // The initializer block and the condition block are always executed. // The afterthought and body block may not be executed. - b.buildForLoop({ - b.reassign(variable: v1, value: b.loadString("foo")) - }, { - b.reassign(variable: v2, value: b.loadString("bar")) - return b.loadBool(false) - }, { - b.reassign(variable: v3, value: b.loadString("baz")) - }) { + b.buildForLoop( + { + b.reassign(variable: v1, value: b.loadString("foo")) + }, + { + b.reassign(variable: v2, value: b.loadString("bar")) + return b.loadBool(false) + }, + { + b.reassign(variable: v3, value: b.loadString("baz")) + } + ) { b.reassign(variable: v4, value: b.loadString("bla")) } @@ -1068,22 +1268,41 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, - { i in XCTAssertEqual(b.type(of: i), .integer); return b.compare(i, with: b.loadInt(10), using: .lessThan) }, - { i in XCTAssertEqual(b.type(of: i), .integer); b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + return b.compare(i, with: b.loadInt(10), using: .lessThan) + }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.unary(.PostInc, i) + } + ) { i in XCTAssertEqual(b.type(of: i), .integer) } - b.buildForLoop(i: { b.loadInt(0) }, - { i in - XCTAssertEqual(b.type(of: i), .integer); - b.buildForLoop(i: { b.loadFloat(12.34) }, { i in XCTAssertEqual(b.type(of: i), .float); return b.loadBool(false) }, { i in XCTAssertEqual(b.type(of: i), .float )}) { i in - XCTAssertEqual(b.type(of: i), .float) - } - return b.compare(i, with: b.loadInt(10), using: .lessThan) + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.buildForLoop( + i: { b.loadFloat(12.34) }, + { i in + XCTAssertEqual(b.type(of: i), .float) + return b.loadBool(false) + }, { i in XCTAssertEqual(b.type(of: i), .float) } + ) { i in + XCTAssertEqual(b.type(of: i), .float) + } + return b.compare(i, with: b.loadInt(10), using: .lessThan) - }, - { i in XCTAssertEqual(b.type(of: i), .integer); b.unary(.PostInc, i) }) { i in + }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.unary(.PostInc, i) + } + ) { i in XCTAssertEqual(b.type(of: i), .integer) } } @@ -1100,10 +1319,13 @@ class JSTyperTests: XCTestCase { b.buildSwitch(on: v2) { swtch in swtch.addCase(v3) { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("baz", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) XCTAssertEqual(b.type(of: v0), .integer) let stringVar = b.loadString("foobar") @@ -1111,10 +1333,13 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .jsString) } swtch.addDefaultCase { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("qux", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "qux"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "qux"])) XCTAssertEqual(b.type(of: v0), .integer) let boolVal = b.loadBool(false) @@ -1122,10 +1347,13 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .boolean) } swtch.addCase(v4) { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("bla", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) XCTAssertEqual(b.type(of: v0), .integer) let floatVar = b.loadFloat(13.37) @@ -1135,7 +1363,8 @@ class JSTyperTests: XCTestCase { } XCTAssertEqual(b.type(of: v0), .float | .boolean | .jsString) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v3), .integer) XCTAssertEqual(b.type(of: v4), .jsString) } @@ -1198,22 +1427,25 @@ class JSTyperTests: XCTestCase { func testDestructObjectTypeInference() { let objectGroups: [ObjectGroup] = [ - ObjectGroup(name: "O", - instanceType: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"]), - properties: [ - "foo": .integer, - "bar": .string, - "baz": .boolean - ], - methods: [:]) + ObjectGroup( + name: "O", + instanceType: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"]), + properties: [ + "foo": .integer, + "bar": .string, + "baz": .boolean, + ], + methods: [:]) ] - let env = JavaScriptEnvironment(additionalBuiltins: [:], additionalObjectGroups: objectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: [:], additionalObjectGroups: objectGroups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() let obj = b.createNamedVariable(forBuiltin: "myO") - b.setType(ofVariable: obj, to: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"])) + b.setType( + ofVariable: obj, to: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"])) let outputs = b.destruct(obj, selecting: ["foo", "bar"], hasRestElement: true) XCTAssertEqual(b.type(of: outputs[0]), .integer) @@ -1251,18 +1483,24 @@ class JSTyperTests: XCTestCase { let structType = b.wasmDefineTypeGroup { let structType = b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), - WasmStructTypeDescription.Field(type: .wasmi64, mutability: true)], + fields: [ + WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), + WasmStructTypeDescription.Field(type: .wasmi64, mutability: true), + ], indexTypes: []) let structType2 = b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), - WasmStructTypeDescription.Field(type: .wasmi64, mutability: true)], + fields: [ + WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), + WasmStructTypeDescription.Field(type: .wasmi64, mutability: true), + ], indexTypes: []) XCTAssert(b.type(of: structType).Is(.wasmTypeDef())) // Despite having identical structure, the two struct types are not comparable. XCTAssertFalse(b.type(of: structType).Is(b.type(of: structType2))) XCTAssertFalse(b.type(of: structType2).Is(b.type(of: structType))) - let desc = b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription + let desc = + b.type(of: structType).wasmTypeDefinition!.description! + as! WasmStructTypeDescription XCTAssertEqual(desc.fields.count, 2) XCTAssertEqual(desc.fields[0].type, .wasmi32) XCTAssertEqual(desc.fields[1].type, .wasmi64) @@ -1270,7 +1508,8 @@ class JSTyperTests: XCTestCase { }[0] XCTAssert(b.type(of: structType).Is(.wasmTypeDef())) - let desc = b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription + let desc = + b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription XCTAssertEqual(desc.fields.count, 2) XCTAssertEqual(desc.fields[0].type, .wasmi32) XCTAssertEqual(desc.fields[1].type, .wasmi64) @@ -1313,7 +1552,8 @@ class JSTyperTests: XCTestCase { // Actions like `setProperty` modify the ILType but do not modify any information stored in // the ObjectGroupManager. b.setProperty("foo", of: object, to: b.loadInt(123)) - XCTAssertEqual(b.type(of: object), + XCTAssertEqual( + b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) let fooPropertyNew = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooPropertyNew), .function([] => .jsString)) @@ -1330,7 +1570,8 @@ class JSTyperTests: XCTestCase { o.addProperty("foo", as: stringVal) } - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) let fooProperty = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooProperty), .jsString) let fooResult = b.callMethod("foo", on: object) @@ -1372,7 +1613,9 @@ class JSTyperTests: XCTestCase { // In JS, the last value a property is set to, overwrites the previous value. Since // Fuzzilli tracks properties and methods separately, they do not overwrite each other in // the ObjectGroupManager (but maybe should). - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) + XCTAssertEqual( + b.type(of: object), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) let fooProperty = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooProperty), .integer) let fooResult = b.callMethod("foo", on: object) @@ -1383,7 +1626,7 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let classDef = b.buildClassDefinition() { cls in + let classDef = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.integer])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -1396,7 +1639,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) XCTAssertEqual(b.currentSuperType(), .object()) XCTAssertEqual(b.type(of: params[1]), .float) @@ -1420,8 +1664,12 @@ class JSTyperTests: XCTestCase { } } - let instanceType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a", "foo", "bar", "baz", "blub"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: classDef), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) + let instanceType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "foo", "bar", "baz", "blub"], + withMethods: ["f"]) + XCTAssertEqual( + b.type(of: classDef), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) let instance = b.construct(classDef, withArgs: [b.loadInt(42)]) @@ -1433,55 +1681,79 @@ class JSTyperTests: XCTestCase { } func testDynamicObjectGroupTypingOfClassesWithSubclasses() { - let fuzzer = makeMockFuzzer() - let b = fuzzer.makeBuilder() + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() - let classDef = b.buildClassDefinition() { cls in - cls.addConstructor(with: .parameters([.integer])) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) - XCTAssertEqual(b.currentSuperType(), .object()) + let classDef = b.buildClassDefinition { cls in + cls.addConstructor(with: .parameters([.integer])) { params in + let this = params[0] + XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) + XCTAssertEqual(b.currentSuperType(), .object()) - XCTAssertEqual(b.type(of: params[1]), .integer) - } + XCTAssertEqual(b.type(of: params[1]), .integer) + } - cls.addInstanceProperty("a") + cls.addInstanceProperty("a") - cls.addInstanceMethod("f", with: .parameters(.float)) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) - XCTAssertEqual(b.currentSuperType(), .object()) + cls.addInstanceMethod("f", with: .parameters(.float)) { params in + let this = params[0] + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual(b.currentSuperType(), .object()) - XCTAssertEqual(b.type(of: params[1]), .float) + XCTAssertEqual(b.type(of: params[1]), .float) - b.doReturn(b.loadString("foobar")) - } - } + b.doReturn(b.loadString("foobar")) + } + } - let instanceType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: classDef), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) + let instanceType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) + XCTAssertEqual( + b.type(of: classDef), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) - let v = b.loadInt(42) - let cls = b.buildClassDefinition(withSuperclass: classDef) { cls in - cls.addInstanceProperty("b", value: v) + let v = b.loadInt(42) + let cls = b.buildClassDefinition(withSuperclass: classDef) { cls in + cls.addInstanceProperty("b", value: v) - cls.addConstructor(with: .parameters([.string])) { params in - XCTAssertEqual(b.currentSuperConstructorType(), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]))) - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) - XCTAssertEqual(b.currentSuperType(), instanceType) + cls.addConstructor(with: .parameters([.string])) { params in + XCTAssertEqual( + b.currentSuperConstructorType(), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [.integer] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], + withMethods: ["f"]))) + let this = params[0] + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual(b.currentSuperType(), instanceType) - b.callSuperConstructor(withArgs: [b.loadFloat(42)]) - } + b.callSuperConstructor(withArgs: [b.loadFloat(42)]) + } - cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) - XCTAssertEqual(b.currentSuperType(), instanceType) - } - } + cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in + let this = params[0] + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual(b.currentSuperType(), instanceType) + } + } - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor2") + .constructor([.string] => .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object(ofGroup: "_fuzz_Constructor2") + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], + withMethods: ["f", "g"]))) let instance = b.construct(cls, withArgs: [b.loadString("bla")]) @@ -1490,12 +1762,10 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(ofProperty: "a", on: instance), .jsAnything) } - func testDynamicObjectGroupTypingOfLiterals() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let int = b.loadInt(42) let object = b.buildObjectLiteral { o in @@ -1505,7 +1775,9 @@ class JSTyperTests: XCTestCase { o.addProperty("bla", as: int) } - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["bla"], withMethods: ["foo"])) + XCTAssertEqual( + b.type(of: object), + .object(ofGroup: "_fuzz_Object0", withProperties: ["bla"], withMethods: ["foo"])) XCTAssertEqual(b.type(ofProperty: "bla", on: object), .integer) } @@ -1519,7 +1791,11 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobalf64: Variable = b.createWasmGlobal(value: .wasmf64(1337), isMutable: false) - XCTAssertEqual(b.type(of: wasmGlobalf64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmf64, isMutable: false))) + XCTAssertEqual( + b.type(of: wasmGlobalf64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmf64, isMutable: false))) let maxPages: Int? = isShared ? 4 : nil let memory = b.createWasmMemory(minPages: 1, maxPages: maxPages, isShared: isShared) @@ -1551,8 +1827,9 @@ class JSTyperTests: XCTestCase { // This forces an import of the wasmGlobalf64, second global function.wasmLoadGlobal(globalVariable: wasmGlobalf64) // This forces an import and a re-export of the jsTag. - function.wasmBuildLegacyTryVoid(body: { _ in }, - catchClauses: [(tag: jsTag, body: {_, _, _ in })]) + function.wasmBuildLegacyTryVoid( + body: { _ in }, + catchClauses: [(tag: jsTag, body: { _, _, _ in })]) function.wasmUnreachable() return [] } @@ -1560,7 +1837,9 @@ class JSTyperTests: XCTestCase { // Function one wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in // Do a store to import the memory. - function.wasmMemoryStore(memory: memory, dynamicOffset: function.consti32(0), value: args[0], storeType: .I32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory, dynamicOffset: function.consti32(0), value: args[0], + storeType: .I32StoreMem, staticOffset: 0) return [function.consti64(1338)] } @@ -1571,25 +1850,38 @@ class JSTyperTests: XCTestCase { } // Function three - wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32, .wasmi64]) { function, label, _ in + wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32, .wasmi64]) { + function, label, _ in return [function.consti32(1), function.consti64(2)] } // Function four - wasmModule.addWasmFunction(with: [] => [ILType.wasmIndexRef(typeDesc, nullability: true)]) { function, label, _ in - return [function.wasmArrayNewDefault(arrayType: typeGroup[0], size: function.consti32(10))] + wasmModule.addWasmFunction( + with: [] => [ILType.wasmIndexRef(typeDesc, nullability: true)] + ) { function, label, _ in + return [ + function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: function.consti32(10)) + ] } - // Function five wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, _ in // This forces an import and we should see a re-exported function on the module. - return [function.wasmJsCall(function: plainFunction, withArgs: [], withWasmSignature: wasmSignature)!] + return [ + function.wasmJsCall( + function: plainFunction, withArgs: [], withWasmSignature: wasmSignature)! + ] } } let exports = module.loadExports() - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports1", withProperties: ["wg0", "iwg0", "wm0", "iwm0", "wex0", "iwex0"], withMethods: ["w0", "w1", "w2", "w3", "w4", "w5", "iw0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports1", + withProperties: ["wg0", "iwg0", "wm0", "iwm0", "wex0", "iwex0"], + withMethods: ["w0", "w1", "w2", "w3", "w4", "w5", "iw0"])) let fun0 = b.methodSignatures(of: module.getExportedMethod(at: 0), on: exports) let fun1 = b.methodSignatures(of: module.getExportedMethod(at: 1), on: exports) @@ -1609,17 +1901,26 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(reexportedFunction, [[] => .object(ofGroup: "_fuzz_Object0")]) let glob0 = b.getProperty("wg0", of: exports) - XCTAssertEqual(b.type(of: glob0), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: glob0), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmi64, isMutable: true))) let glob1 = b.getProperty("iwg0", of: exports) - XCTAssertEqual(b.type(of: glob1), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmf64, isMutable: false))) + XCTAssertEqual( + b.type(of: glob1), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmf64, isMutable: false))) let mem0 = b.getProperty("wm0", of: exports) let memType = ILType.wasmMemory(limits: Limits(min: 3, max: maxPages), isShared: isShared) XCTAssertEqual(b.type(of: mem0), memType) let importedMem = b.getProperty("iwm0", of: exports) - let importedMemType = ILType.wasmMemory(limits: Limits(min: 1, max: maxPages), isShared: isShared) + let importedMemType = ILType.wasmMemory( + limits: Limits(min: 1, max: maxPages), isShared: isShared) XCTAssertEqual(b.type(of: importedMem), importedMemType) let reexportedJsTag = b.getProperty("iwex0", of: exports) @@ -1643,7 +1944,9 @@ class JSTyperTests: XCTestCase { let signatures = b.methodSignatures(of: "indexOf", on: arrayProto) XCTAssertEqual([[.jsAnything, .opt(.integer)] => .integer], signatures) let indexOf = b.getProperty("indexOf", of: arrayProto) - XCTAssertEqual(b.type(of: indexOf), .unboundFunction([.jsAnything, .opt(.integer)] => .integer, receiver: .jsArray)) + XCTAssertEqual( + b.type(of: indexOf), + .unboundFunction([.jsAnything, .opt(.integer)] => .integer, receiver: .jsArray)) // Date.prototype let dateBuiltin = b.createNamedVariable(forBuiltin: "Date") @@ -1659,7 +1962,8 @@ class JSTyperTests: XCTestCase { let promiseProto = b.getProperty("prototype", of: promiseBuiltin) XCTAssert(b.type(of: dateProto).Is(.object(ofGroup: "Date.prototype"))) let then = b.getProperty("then", of: promiseProto) - XCTAssertEqual(b.type(of: then), .unboundFunction([.function()] => .jsPromise, receiver: .jsPromise)) + XCTAssertEqual( + b.type(of: then), .unboundFunction([.function()] => .jsPromise, receiver: .jsPromise)) // ArrayBuffer.prototype let arrayBufferBuiltin = b.createNamedVariable(forBuiltin: "ArrayBuffer") @@ -1667,15 +1971,22 @@ class JSTyperTests: XCTestCase { let arrayBufferProto = b.getProperty("prototype", of: arrayBufferBuiltin) XCTAssert(b.type(of: arrayBufferProto).Is(.object(ofGroup: "ArrayBuffer.prototype"))) let resize = b.getProperty("resize", of: arrayBufferProto) - XCTAssertEqual(b.type(of: resize), .unboundFunction([.integer] => .undefined, receiver: .jsArrayBuffer)) + XCTAssertEqual( + b.type(of: resize), .unboundFunction([.integer] => .undefined, receiver: .jsArrayBuffer) + ) // ArrayBuffer.prototype let sharedArrayBufferBuiltin = b.createNamedVariable(forBuiltin: "SharedArrayBuffer") - XCTAssert(b.type(of: sharedArrayBufferBuiltin).Is(.object(ofGroup: "SharedArrayBufferConstructor"))) + XCTAssert( + b.type(of: sharedArrayBufferBuiltin).Is( + .object(ofGroup: "SharedArrayBufferConstructor"))) let sharedArrayBufferProto = b.getProperty("prototype", of: sharedArrayBufferBuiltin) - XCTAssert(b.type(of: sharedArrayBufferProto).Is(.object(ofGroup: "SharedArrayBuffer.prototype"))) + XCTAssert( + b.type(of: sharedArrayBufferProto).Is(.object(ofGroup: "SharedArrayBuffer.prototype"))) let grow = b.getProperty("grow", of: sharedArrayBufferProto) - XCTAssertEqual(b.type(of: grow), .unboundFunction([.number] => .undefined, receiver: .jsSharedArrayBuffer)) + XCTAssertEqual( + b.type(of: grow), + .unboundFunction([.number] => .undefined, receiver: .jsSharedArrayBuffer)) // Temporal objects let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") @@ -1685,13 +1996,16 @@ class JSTyperTests: XCTestCase { let instantProto = b.getProperty("prototype", of: instantBuiltin) XCTAssert(b.type(of: instantProto).Is(.object(ofGroup: "Temporal.Instant.prototype"))) let instantRound = b.getProperty("round", of: instantProto) - XCTAssert(b.type(of: instantRound).Is(.unboundFunction([.plain(OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType)] => ILType.jsTemporalInstant, - receiver: .jsTemporalInstant))) + XCTAssert( + b.type(of: instantRound).Is( + .unboundFunction( + [.plain(OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType)] + => ILType.jsTemporalInstant, + receiver: .jsTemporalInstant))) let randomString = b.randomVariable(forUseAs: .string) let fromCall = b.callMethod("from", on: instantBuiltin, withArgs: [randomString]) XCTAssert(b.type(of: fromCall).Is(.jsTemporalInstant)) - // We don't test Instant's prototype, since Instant only has nontrivial methods that // use options bag types that are still in flux. @@ -1700,8 +2014,9 @@ class JSTyperTests: XCTestCase { let durationProto = b.getProperty("prototype", of: durationBuiltin) XCTAssert(b.type(of: durationProto).Is(.object(ofGroup: "Temporal.Duration.prototype"))) let negated = b.getProperty("negated", of: durationProto) - XCTAssertEqual(b.type(of: negated), .unboundFunction([] => .jsTemporalDuration, receiver: .jsTemporalDuration)) - + XCTAssertEqual( + b.type(of: negated), + .unboundFunction([] => .jsTemporalDuration, receiver: .jsTemporalDuration)) } @@ -1718,7 +2033,8 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") let durationBuiltin = b.getProperty("Duration", of: temporalBuiltin) - let duration = b.callMethod("from", on: durationBuiltin, withArgs: [b.loadString("P10D")]) + let duration = b.callMethod( + "from", on: durationBuiltin, withArgs: [b.loadString("P10D")]) XCTAssert(b.type(of: duration).Is(.jsTemporalDuration)) let signature = chooseUniform(from: b.methodSignatures(of: "round", on: duration)) let args = b.findOrGenerateArguments(forSignature: signature) @@ -1759,13 +2075,15 @@ class JSTyperTests: XCTestCase { let wasm = b.createNamedVariable(forBuiltin: "WebAssembly") XCTAssert(b.type(of: wasm).Is(.object(ofGroup: "WebAssembly"))) let wasmModuleConstructor = b.getProperty("Module", of: wasm) - XCTAssert(b.type(of: wasmModuleConstructor).Is(.object(ofGroup: "WebAssemblyModuleConstructor"))) - let wasmModule = b.construct(wasmModuleConstructor) // In theory this needs arguments. + XCTAssert( + b.type(of: wasmModuleConstructor).Is(.object(ofGroup: "WebAssemblyModuleConstructor"))) + let wasmModule = b.construct(wasmModuleConstructor) // In theory this needs arguments. XCTAssert(b.type(of: wasmModule).Is(.object(ofGroup: "WebAssembly.Module"))) let wasmGlobalConstructor = b.getProperty("Global", of: wasm) - XCTAssert(b.type(of: wasmGlobalConstructor).Is(.object(ofGroup: "WebAssemblyGlobalConstructor"))) - let wasmGlobal = b.construct(wasmGlobalConstructor) // In theory this needs arguments. + XCTAssert( + b.type(of: wasmGlobalConstructor).Is(.object(ofGroup: "WebAssemblyGlobalConstructor"))) + let wasmGlobal = b.construct(wasmGlobalConstructor) // In theory this needs arguments. // We do not type the constructed value as globals as the "WasmGlobal" object group expects // to have a WasmTypeExtension. XCTAssertFalse(b.type(of: wasmGlobal).Is(.object(ofGroup: "WasmGlobal"))) @@ -1777,56 +2095,75 @@ class JSTyperTests: XCTestCase { // WebAssembly.Global.prototype.valueOf() function. let globalPrototype = b.getProperty("prototype", of: wasmGlobalConstructor) let valueOf = b.getProperty("valueOf", of: globalPrototype) - XCTAssertEqual(b.type(of: valueOf), .unboundFunction([] => .jsAnything, receiver: .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"]))) + XCTAssertEqual( + b.type(of: valueOf), + .unboundFunction( + [] => .jsAnything, + receiver: .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"]))) let wasmMemoryConstructor = b.getProperty("Memory", of: wasm) - let wasmMemory = b.construct(wasmMemoryConstructor) // In theory this needs arguments. + let wasmMemory = b.construct(wasmMemoryConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmMemory).Is(.object(ofGroup: "WasmMemory"))) let realWasmMemory = b.createWasmMemory(minPages: 1, maxPages: 1, isShared: false) XCTAssert(b.type(of: realWasmMemory).Is(.object(ofGroup: "WasmMemory"))) XCTAssert(b.type(of: realWasmMemory).Is(ObjectGroup.jsWasmMemory.instanceType)) let memoryPrototype = b.getProperty("prototype", of: wasmMemoryConstructor) let grow = b.getProperty("grow", of: memoryPrototype) - XCTAssert(b.type(of: grow).Is(.unboundFunction([.number] => .number, receiver: .object(ofGroup: "WasmMemory")))) + XCTAssert( + b.type(of: grow).Is( + .unboundFunction([.number] => .number, receiver: .object(ofGroup: "WasmMemory")))) let wasmTableConstructor = b.getProperty("Table", of: wasm) - let wasmTable = b.construct(wasmTableConstructor) // In theory this needs arguments. + let wasmTable = b.construct(wasmTableConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmTable).Is(.object(ofGroup: "WasmTable"))) - let realWasmTable = b.createWasmTable(elementType: .wasmAnyRef(), limits: .init(min: 0), isTable64: false) + let realWasmTable = b.createWasmTable( + elementType: .wasmAnyRef(), limits: .init(min: 0), isTable64: false) XCTAssert(b.type(of: realWasmTable).Is(.object(ofGroup: "WasmTable"))) XCTAssert(b.type(of: realWasmTable).Is(ObjectGroup.wasmTable.instanceType)) let tablePrototype = b.getProperty("prototype", of: wasmTableConstructor) let tableGrow = b.getProperty("grow", of: tablePrototype) - XCTAssert(b.type(of: tableGrow).Is(.unboundFunction([.number, .opt(.jsAnything)] => .number, receiver: .object(ofGroup: "WasmTable")))) + XCTAssert( + b.type(of: tableGrow).Is( + .unboundFunction( + [.number, .opt(.jsAnything)] => .number, receiver: .object(ofGroup: "WasmTable") + ))) let wasmTagConstructor = b.getProperty("Tag", of: wasm) - let wasmTag = b.construct(wasmTagConstructor) // In theory this needs arguments. + let wasmTag = b.construct(wasmTagConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmTag).Is(.object(ofGroup: "WasmTag"))) let realWasmTag = b.createWasmTag(parameterTypes: [.wasmi32]) XCTAssert(b.type(of: realWasmTag).Is(.object(ofGroup: "WasmTag"))) let tagPrototype = b.getProperty("prototype", of: wasmTagConstructor) - XCTAssertEqual(b.type(of: tagPrototype), - .object(ofGroup: "WasmTag.prototype", withProperties: ["constructor"])) + XCTAssertEqual( + b.type(of: tagPrototype), + .object(ofGroup: "WasmTag.prototype", withProperties: ["constructor"])) let wasmExceptionConstructor = b.getProperty("Exception", of: wasm) - let wasmException = b.construct(wasmExceptionConstructor) // In theory this needs arguments. + let wasmException = b.construct(wasmExceptionConstructor) // In theory this needs arguments. XCTAssert(b.type(of: wasmException).Is(.object(ofGroup: "WebAssembly.Exception"))) let isResult = b.callMethod("is", on: wasmException, withArgs: [realWasmTag]) XCTAssertEqual(b.type(of: isResult), .boolean) let exceptionPrototype = b.getProperty("prototype", of: wasmExceptionConstructor) - XCTAssert(b.type(of: exceptionPrototype).Is(ObjectGroup.jsWebAssemblyExceptionPrototype.instanceType)) + XCTAssert( + b.type(of: exceptionPrototype).Is( + ObjectGroup.jsWebAssemblyExceptionPrototype.instanceType)) let exceptionIs = b.getProperty("is", of: exceptionPrototype) - XCTAssert(b.type(of: exceptionIs).Is(.unboundFunction([.plain(ObjectGroup.jsWasmTag.instanceType)] => ILType.boolean, receiver: .object(ofGroup: "WebAssembly.Exception")))) + XCTAssert( + b.type(of: exceptionIs).Is( + .unboundFunction( + [.plain(ObjectGroup.jsWasmTag.instanceType)] => ILType.boolean, + receiver: .object(ofGroup: "WebAssembly.Exception")))) } func testProducingGenerators() { // Make a simple object - let mockEnum = ILType.enumeration(ofName: "MockEnum", withValues: ["mockValue"]); + let mockEnum = ILType.enumeration(ofName: "MockEnum", withValues: ["mockValue"]) let mockObject = ObjectGroup( name: "MockObject", instanceType: nil, properties: [ - "mockField" : mockEnum + "mockField": mockEnum ], methods: [:] ) @@ -1845,7 +2182,7 @@ class JSTyperTests: XCTestCase { return variable } - let mockNamedString = ILType.namedString(ofName: "NamedString"); + let mockNamedString = ILType.namedString(ofName: "NamedString") func generateString() -> String { callCount += 1 return "mockStringValue" @@ -1854,7 +2191,8 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() fuzzer.environment.registerObjectGroup(mockObject) fuzzer.environment.registerEnumeration(mockEnum) - fuzzer.environment.addProducingGenerator(forType: mockObject.instanceType, with: generateObject) + fuzzer.environment.addProducingGenerator( + forType: mockObject.instanceType, with: generateObject) fuzzer.environment.addNamedStringGenerator(forType: mockNamedString, with: generateString) let b = fuzzer.makeBuilder() b.buildPrefix() @@ -1866,7 +2204,6 @@ class JSTyperTests: XCTestCase { // Test that the returned variable matches the generated one XCTAssertEqual(variable, returnedVar) - // Try to get it to invoke the string generator let variable2 = b.findOrGenerateType(mockNamedString) // Test that the generator was invoked @@ -1887,7 +2224,10 @@ class JSTyperTests: XCTestCase { } func testFindConstructor() { - for ctor in ["TemporalPlainMonthDayConstructor", "DateConstructor", "PromiseConstructor", "SymbolConstructor", "TemporalZonedDateTimeConstructor"] { + for ctor in [ + "TemporalPlainMonthDayConstructor", "DateConstructor", "PromiseConstructor", + "SymbolConstructor", "TemporalZonedDateTimeConstructor", + ] { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") @@ -1909,7 +2249,7 @@ class JSTyperTests: XCTestCase { XCTAssert(unionType.Is(.jsArrayBuffer | .jsSharedArrayBuffer)) XCTAssert(unionType.MayBe(.jsArrayBuffer)) XCTAssert(unionType.MayBe(.jsSharedArrayBuffer)) - XCTAssertFalse(unionType.Is(.jsArrayBuffer)) // It's not *definitely* an ArrayBuffer + XCTAssertFalse(unionType.Is(.jsArrayBuffer)) // It's not *definitely* an ArrayBuffer XCTAssertFalse(unionType.Is(.jsSharedArrayBuffer)) // Common properties should be preserved @@ -1917,8 +2257,8 @@ class JSTyperTests: XCTestCase { XCTAssert(unionType.methods.contains("slice")) // Disjoint properties/methods should be removed in the union - XCTAssertFalse(unionType.methods.contains("resize")) // Only on ArrayBuffer - XCTAssertFalse(unionType.methods.contains("grow")) // Only on SharedArrayBuffer + XCTAssertFalse(unionType.methods.contains("resize")) // Only on ArrayBuffer + XCTAssertFalse(unionType.methods.contains("grow")) // Only on SharedArrayBuffer XCTAssertNil(unionType.group) } diff --git a/Tests/FuzzilliTests/Leb128Test.swift b/Tests/FuzzilliTests/Leb128Test.swift index 0c6ef64f1..701381adb 100644 --- a/Tests/FuzzilliTests/Leb128Test.swift +++ b/Tests/FuzzilliTests/Leb128Test.swift @@ -13,11 +13,12 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class Leb128Tests: XCTestCase { func testUnsignedEncode() { - let encoded = Leb128.unsignedEncode(624485); - XCTAssertEqual(encoded.map({ String(format: "%02hhx", $0)}).joined(), "e58e26") + let encoded = Leb128.unsignedEncode(624485) + XCTAssertEqual(encoded.map({ String(format: "%02hhx", $0) }).joined(), "e58e26") } } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 0f1a51621..0840baf24 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class LifterTests: XCTestCase { @@ -88,12 +89,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - v1.r = SomeObj.foo.bar.baz(42, 42); - v1.s = Math.random() + 13.37; - v1.s; + const v1 = new Object(); + v1.r = SomeObj.foo.bar.baz(42, 42); + v1.s = Math.random() + 13.37; + v1.s; - """ + """ XCTAssertEqual(actual, expected) } @@ -116,11 +117,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - const t1 = SomeObj.foo.bar.baz; - v1.r = t1(42, 42); + const v1 = new Object(); + const t1 = SomeObj.foo.bar.baz; + v1.r = t1(42, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -200,44 +201,43 @@ class LifterTests: XCTestCase { res = b.callMethod("func36", on: effectful, withArgs: [x, z, tmp]) b.setProperty("res12", of: obj, to: res) - let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - v1.res1 = effectful.func1() + effectful.func2(); - const v6 = effectful.func3(); - effectful.func4(); - v1.res2 = v6 + 13.37; - effectful.func5(); - const v11 = effectful.func6(); - effectful.func7(); - v1.res3 = -v11; - v1.res4 = 13.37; - const v15 = effectful.func8(); - const v16 = effectful.func9(); - const v17 = effectful.func10(v15); - v1.res5 = v16; - v1.res6 = v17; - effectful.func11(); - const v19 = effectful.func12(); - v1.res7 = (effectful.func13() + (effectful.func14() * effectful.func15())) / v19; - v1.res8 = effectful.func19(effectful.func16(), effectful.func17(), effectful.func18()); - const v30 = effectful.func20(); - v1.res9 = effectful.func23(effectful.func21(), effectful.func22(), v30); - const v34 = effectful.func24(); - const v35 = effectful.func25(); - v1.res10 = effectful.func27(v34, effectful.func26(), v35); - const v38 = effectful.func28(); - const v39 = effectful.func29(); - v1.res11 = effectful.func31(effectful.func30(), v38, v39); - const v42 = effectful.func32(); - const v43 = effectful.func33(); - const v44 = effectful.func34(); - v1.res12 = effectful.func36(v42, v44, effectful.func35(v43)); - - """ + const v1 = new Object(); + v1.res1 = effectful.func1() + effectful.func2(); + const v6 = effectful.func3(); + effectful.func4(); + v1.res2 = v6 + 13.37; + effectful.func5(); + const v11 = effectful.func6(); + effectful.func7(); + v1.res3 = -v11; + v1.res4 = 13.37; + const v15 = effectful.func8(); + const v16 = effectful.func9(); + const v17 = effectful.func10(v15); + v1.res5 = v16; + v1.res6 = v17; + effectful.func11(); + const v19 = effectful.func12(); + v1.res7 = (effectful.func13() + (effectful.func14() * effectful.func15())) / v19; + v1.res8 = effectful.func19(effectful.func16(), effectful.func17(), effectful.func18()); + const v30 = effectful.func20(); + v1.res9 = effectful.func23(effectful.func21(), effectful.func22(), v30); + const v34 = effectful.func24(); + const v35 = effectful.func25(); + v1.res10 = effectful.func27(v34, effectful.func26(), v35); + const v38 = effectful.func28(); + const v39 = effectful.func29(); + v1.res11 = effectful.func31(effectful.func30(), v38, v39); + const v42 = effectful.func32(); + const v43 = effectful.func33(); + const v44 = effectful.func34(); + v1.res12 = effectful.func36(v42, v44, effectful.func35(v43)); + + """ XCTAssertEqual(actual, expected) } @@ -260,11 +260,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - if (someValue < computeThreshold()) { - doSomething(); - } + if (someValue < computeThreshold()) { + doSomething(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -285,13 +285,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - const v2 = computeNumIterations(); - while (v0 < v2) { - v0++; - } + let v0 = 0; + const v2 = computeNumIterations(); + while (v0 < v2) { + v0++; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -315,12 +315,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - const v6 = func2(func1(1337)); - v1.x = v6; - v1.y = v6; + const v1 = new Object(); + const v6 = func2(func1(1337)); + v1.x = v6; + v1.y = v6; - """ + """ XCTAssertEqual(actual, expected) } @@ -340,11 +340,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - [NaN,NaN,NaN]; - let v2 = NaN; - v2 = 13.37; + [NaN,NaN,NaN]; + let v2 = NaN; + v2 = 13.37; - """ + """ XCTAssertEqual(actual, expected) } @@ -372,12 +372,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - const v2 = a1.x; - return a1.y ? v2 : a1.z; - } + function f0(a1) { + const v2 = a1.x; + return a1.y ? v2 : a1.z; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -403,11 +403,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - return Math.sqrt((a1.x ** 2) + (a1.y ** 2)); - } + function f0(a1) { + return Math.sqrt((a1.x ** 2) + (a1.y ** 2)); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -421,33 +421,34 @@ class LifterTests: XCTestCase { // operation where we force the object to be a variable. let i1 = b.loadInt(0) let i2 = b.loadInt(10) - b.buildDoWhileLoop(do: { - // The SetElement will "un-inline" i2, but for the do-while loop we'll still need the inlined expression (`10`). - b.setElement(0, of: i2, to: i1) - b.setElement(1, of: i2, to: i1) - b.unary(.PostInc, i1) - }, while: { b.compare(i1, with: i2, using: .lessThan) }) + b.buildDoWhileLoop( + do: { + // The SetElement will "un-inline" i2, but for the do-while loop we'll still need the inlined expression (`10`). + b.setElement(0, of: i2, to: i1) + b.setElement(1, of: i2, to: i1) + b.unary(.PostInc, i1) + }, while: { b.compare(i1, with: i2, using: .lessThan) }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - do { - const t2 = 10; - t2[0] = v0; - const t4 = 10; - t4[1] = v0; - v0++; - } while (v0 < 10) + let v0 = 0; + do { + const t2 = 10; + t2[0] = v0; + const t4 = 10; + t4[1] = v0; + v0++; + } while (v0 < 10) - """ + """ XCTAssertEqual(actual, expected) } func testForceVariableDefinitions() { - let createProgram = {(config: Configuration) in + let createProgram = { (config: Configuration) in let fuzzer = makeMockFuzzer(config: config) let b = fuzzer.makeBuilder() let dateBuiltin = b.createNamedVariable(forBuiltin: "Date") @@ -462,20 +463,20 @@ class LifterTests: XCTestCase { let config = Configuration(logLevel: .warning) let actual = createProgram(config) let expected = """ - Date.prototype; - new Array(); + Date.prototype; + new Array(); - """ + """ XCTAssertEqual(actual, expected) } do { let config = Configuration(logLevel: .warning, forDifferentialFuzzing: true) let actual = createProgram(config) let expected = """ - const v1 = Date.prototype; - const v3 = new Array(); + const v1 = Date.prototype; + const v3 = new Array(); - """ + """ XCTAssertEqual(actual, expected) } } @@ -494,16 +495,17 @@ class LifterTests: XCTestCase { b.loadInt(42) b.loadString("foobar") b.createNamedVariable("nonexistant", declarationMode: .none) - let v = b.createNamedVariable("alsoNonexistantButSafeToAccessViaTypeOf", declarationMode: .none) + let v = b.createNamedVariable( + "alsoNonexistantButSafeToAccessViaTypeOf", declarationMode: .none) b.typeof(v) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - typeof alsoNonexistantButSafeToAccessViaTypeOf; + typeof alsoNonexistantButSafeToAccessViaTypeOf; - """ + """ XCTAssertEqual(actual, expected) } @@ -555,39 +557,39 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = "foobar" + 42; - const v7 = Symbol.toPrimitive; - const v20 = { - p1: 42, - __proto__: null, - 0: 13.37, - [-1]: 13.37, - ["foobar"]: "foobar", - p2: 13.37, - [v4]: 42, - __proto__: null, - m(a9, a10) { - return a9 - a10; - }, - [v7]() { - return 42; - }, - get prop() { - return this.p; - }, - set prop(a16) { - this.p = a16; - }, - get ["foobar"]() { - return 42; - }, - set ["foobar"](a19) { - this.p = a19; - }, - ...SomeObject, - }; + const v4 = "foobar" + 42; + const v7 = Symbol.toPrimitive; + const v20 = { + p1: 42, + __proto__: null, + 0: 13.37, + [-1]: 13.37, + ["foobar"]: "foobar", + p2: 13.37, + [v4]: 42, + __proto__: null, + m(a9, a10) { + return a9 - a10; + }, + [v7]() { + return 42; + }, + get prop() { + return this.p; + }, + set prop(a16) { + this.p = a16; + }, + get ["foobar"]() { + return 42; + }, + set ["foobar"](a19) { + this.p = a19; + }, + ...SomeObject, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -597,7 +599,7 @@ class LifterTests: XCTestCase { let v = b.loadInt(42) b.buildObjectLiteral { obj in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { obj.addProperty(name, as: v) obj.addMethod(name, with: .parameters(n: 0)) { args in } @@ -608,34 +610,34 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v9 = { - "???": 42, - "???"() { - }, - 0: 42, - 0() { - }, - "01": 42, - "01"() { - }, - 1: 42, - 1() { - }, - "0.1": 42, - "0.1"() { - }, - "-1": 42, - "-1"() { - }, - $valid_id_42: 42, - $valid_id_42() { - }, - "42_invalid_id": 42, - "42_invalid_id"() { - }, - }; + const v9 = { + "???": 42, + "???"() { + }, + 0: 42, + 0() { + }, + "01": 42, + "01"() { + }, + 1: 42, + 1() { + }, + "0.1": 42, + "0.1"() { + }, + "-1": 42, + "-1"() { + }, + $valid_id_42: 42, + $valid_id_42() { + }, + "42_invalid_id": 42, + "42_invalid_id"() { + }, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -645,7 +647,7 @@ class LifterTests: XCTestCase { let v = b.loadInt(42) b.buildObjectLiteral { obj in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { obj.addGetter(for: name) { _ in b.doReturn(v) } obj.addSetter(for: name) { _, _ in } } @@ -655,50 +657,50 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v25 = { - get "???"() { - return 42; - }, - set "???"(a3) { - }, - get 0() { - return 42; - }, - set 0(a6) { - }, - get "01"() { - return 42; - }, - set "01"(a9) { - }, - get 1() { - return 42; - }, - set 1(a12) { - }, - get "0.1"() { - return 42; - }, - set "0.1"(a15) { - }, - get "-1"() { - return 42; - }, - set "-1"(a18) { - }, - get $valid_id_42() { - return 42; - }, - set $valid_id_42(a21) { - }, - get "42_invalid_id"() { - return 42; - }, - set "42_invalid_id"(a24) { - }, - }; + const v25 = { + get "???"() { + return 42; + }, + set "???"(a3) { + }, + get 0() { + return 42; + }, + set 0(a6) { + }, + get "01"() { + return 42; + }, + set "01"(a9) { + }, + get 1() { + return 42; + }, + set 1(a12) { + }, + get "0.1"() { + return 42; + }, + set "0.1"(a15) { + }, + get "-1"() { + return 42; + }, + set "-1"(a18) { + }, + get $valid_id_42() { + return 42; + }, + set $valid_id_42(a21) { + }, + get "42_invalid_id"() { + return 42; + }, + set "42_invalid_id"(a24) { + }, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -719,9 +721,9 @@ class LifterTests: XCTestCase { // These must not lift to something like "{ foo: 1, bar: 2 };" as that would be invalid: // the parser cannot distinguish it from a block statement. let expected = """ - const v2 = { foo: 1, bar: 2 }; + const v2 = { foo: 1, bar: 2 }; - """ + """ XCTAssertEqual(actual, expected) } @@ -756,15 +758,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - print({}); - print({ foo: 42, bar: 13.37, 42: "foo" }); - const v9 = { - baz() { - }, - }; - print(v9); + print({}); + print({ foo: 42, bar: 13.37, 42: "foo" }); + const v9 = { + baz() { + }, + }; + print(v9); - """ + """ XCTAssertEqual(actual, expected) } @@ -778,7 +780,7 @@ class LifterTests: XCTestCase { let baz42 = b.binary(baz, i, with: .Add) let toPrimitive = b.createSymbolProperty("toPrimitive") let sm = b.loadString("sm") - let C = b.buildClassDefinition() { cls in + let C = b.buildClassDefinition { cls in cls.addInstanceProperty("foo") cls.addInstanceProperty("bar", value: baz) cls.addInstanceElement(0, value: i) @@ -876,88 +878,88 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v3 = "baz" + 42; - const v5 = Symbol.toPrimitive; - class C7 { - foo; - bar = "baz"; - 0 = 42; - 1; - [-1]; - [v3]; - [2] = v3; - constructor(a9) { - this.foo = a9; - } - m() { - return this.foo; - } - [v5]() { - return this.foo; - } - get baz() { - return 1337; - } - set baz(a17) { - } - get ["baz"]() { - return 1337; - } - set ["baz"](a21) { - } - static foo; - static { - this.foo = 42; - } - static bar = "baz"; - static 0 = 42; - static 1; - static [-1]; - static [v3]; - static [2] = v3; - static m() { - return this.foo; - } - ["sm"]() { - return this.foo; - } - static get baz() { - return 1337; - } - static set baz(a30) { - } - static get ["baz"]() { - return 1337; - } - static set ["baz"](a34) { - } - #ifoo; - #ibar = "baz"; - #im() { - const v36 = this.#ifoo; - this.#ibar = v36; - return v36; - } - #in(a38) { - this.#im(); - this.#ibar += a38; - } - static #sfoo; - static #sbar = "baz"; - static #sm() { - const v41 = this.#sfoo; - this.#sbar = v41; - return v41; - } - static #sn(a43) { - this.#sm(); - this.#sbar += a43; + const v3 = "baz" + 42; + const v5 = Symbol.toPrimitive; + class C7 { + foo; + bar = "baz"; + 0 = 42; + 1; + [-1]; + [v3]; + [2] = v3; + constructor(a9) { + this.foo = a9; + } + m() { + return this.foo; + } + [v5]() { + return this.foo; + } + get baz() { + return 1337; + } + set baz(a17) { + } + get ["baz"]() { + return 1337; + } + set ["baz"](a21) { + } + static foo; + static { + this.foo = 42; + } + static bar = "baz"; + static 0 = 42; + static 1; + static [-1]; + static [v3]; + static [2] = v3; + static m() { + return this.foo; + } + ["sm"]() { + return this.foo; + } + static get baz() { + return 1337; + } + static set baz(a30) { + } + static get ["baz"]() { + return 1337; + } + static set ["baz"](a34) { + } + #ifoo; + #ibar = "baz"; + #im() { + const v36 = this.#ifoo; + this.#ibar = v36; + return v36; + } + #in(a38) { + this.#im(); + this.#ibar += a38; + } + static #sfoo; + static #sbar = "baz"; + static #sm() { + const v41 = this.#sfoo; + this.#sbar = v41; + return v41; + } + static #sn(a43) { + this.#sm(); + this.#sbar += a43; + } } - } - new C7(42); - C7 = Uint8Array; + new C7(42); + C7 = Uint8Array; - """ + """ XCTAssertEqual(actual, expected) } @@ -967,8 +969,8 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let v = b.loadInt(42) - b.buildClassDefinition() { cls in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.buildClassDefinition { cls in + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { cls.addInstanceProperty(name, value: v) cls.addStaticProperty(name, value: v) cls.addInstanceMethod(name, with: .parameters(n: 0)) { params in @@ -982,58 +984,58 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C1 { - "???" = 42; - static "???" = 42; - "???"() { - } - static "???"() { - } - 0 = 42; - static 0 = 42; - 0() { - } - static 0() { - } - "01" = 42; - static "01" = 42; - "01"() { - } - static "01"() { - } - 1 = 42; - static 1 = 42; - 1() { - } - static 1() { - } - "0.1" = 42; - static "0.1" = 42; - "0.1"() { - } - static "0.1"() { - } - "-1" = 42; - static "-1" = 42; - "-1"() { - } - static "-1"() { - } - $valid_id_42 = 42; - static $valid_id_42 = 42; - $valid_id_42() { - } - static $valid_id_42() { - } - "42_invalid_id" = 42; - static "42_invalid_id" = 42; - "42_invalid_id"() { - } - static "42_invalid_id"() { + class C1 { + "???" = 42; + static "???" = 42; + "???"() { + } + static "???"() { + } + 0 = 42; + static 0 = 42; + 0() { + } + static 0() { + } + "01" = 42; + static "01" = 42; + "01"() { + } + static "01"() { + } + 1 = 42; + static 1 = 42; + 1() { + } + static 1() { + } + "0.1" = 42; + static "0.1" = 42; + "0.1"() { + } + static "0.1"() { + } + "-1" = 42; + static "-1" = 42; + "-1"() { + } + static "-1"() { + } + $valid_id_42 = 42; + static $valid_id_42 = 42; + $valid_id_42() { + } + static $valid_id_42() { + } + "42_invalid_id" = 42; + static "42_invalid_id" = 42; + "42_invalid_id"() { + } + static "42_invalid_id"() { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -1042,8 +1044,8 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.buildClassDefinition { cls in + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { cls.addInstanceGetter(for: name) { this in } cls.addStaticGetter(for: name) { this in @@ -1059,74 +1061,74 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - get "???"() { - } - static get "???"() { - } - set "???"(a4) { - } - static set "???"(a6) { - } - get 0() { - } - static get 0() { - } - set 0(a10) { - } - static set 0(a12) { - } - get "01"() { - } - static get "01"() { - } - set "01"(a16) { - } - static set "01"(a18) { - } - get 1() { - } - static get 1() { - } - set 1(a22) { - } - static set 1(a24) { - } - get "0.1"() { - } - static get "0.1"() { - } - set "0.1"(a28) { - } - static set "0.1"(a30) { - } - get "-1"() { - } - static get "-1"() { - } - set "-1"(a34) { - } - static set "-1"(a36) { - } - get $valid_id_42() { - } - static get $valid_id_42() { - } - set $valid_id_42(a40) { - } - static set $valid_id_42(a42) { - } - get "42_invalid_id"() { - } - static get "42_invalid_id"() { - } - set "42_invalid_id"(a46) { - } - static set "42_invalid_id"(a48) { + class C0 { + get "???"() { + } + static get "???"() { + } + set "???"(a4) { + } + static set "???"(a6) { + } + get 0() { + } + static get 0() { + } + set 0(a10) { + } + static set 0(a12) { + } + get "01"() { + } + static get "01"() { + } + set "01"(a16) { + } + static set "01"(a18) { + } + get 1() { + } + static get 1() { + } + set 1(a22) { + } + static set 1(a24) { + } + get "0.1"() { + } + static get "0.1"() { + } + set "0.1"(a28) { + } + static set "0.1"(a30) { + } + get "-1"() { + } + static get "-1"() { + } + set "-1"(a34) { + } + static set "-1"(a36) { + } + get $valid_id_42() { + } + static get $valid_id_42() { + } + set $valid_id_42(a40) { + } + static set $valid_id_42(a42) { + } + get "42_invalid_id"() { + } + static get "42_invalid_id"() { + } + set "42_invalid_id"(a46) { + } + static set "42_invalid_id"(a48) { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -1147,14 +1149,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = class { - 1; - } - let d = v0; - new v0(); - new d(); + const v0 = class { + 1; + } + let d = v0; + new v0(); + new d(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1171,13 +1173,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = class { - } - const v1 = class extends v0 { - } - new v1(); + const v0 = class { + } + const v1 = class extends v0 { + } + new v1(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1199,7 +1201,7 @@ class LifterTests: XCTestCase { let va = b.createArray(with: initialValues) b.createArray(with: [b.loadInt(301), b.loadUndefined()]) b.createArray(with: [b.loadUndefined()]) - b.createArray(with: [va, b.loadUndefined()], spreading: [true,false]) + b.createArray(with: [va, b.loadUndefined()], spreading: [true, false]) b.createArray(with: [b.loadUndefined()], spreading: [false]) b.createIntArray(with: [1, 2, 3, 4]) b.createFloatArray(with: [1.1, 2.2, 3.3, 4.4]) @@ -1208,16 +1210,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v6 = "foobar"; - const v8 = [1,2,,4,,6,v6 = undefined]; - [301,,]; - [,]; - [...v8,,]; - [,]; - [1,2,3,4]; - [1.1,2.2,3.3,4.4]; - - """ + let v6 = "foobar"; + const v8 = [1,2,,4,,6,v6 = undefined]; + [301,,]; + [,]; + [...v8,,]; + [,]; + [1,2,3,4]; + [1.1,2.2,3.3,4.4]; + + """ XCTAssertEqual(actual, expected) } @@ -1238,10 +1240,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - [42,,,42]; - [,,]; + [42,,,42]; + [,,]; - """ + """ XCTAssertEqual(actual, expected) } @@ -1264,10 +1266,10 @@ class LifterTests: XCTestCase { // TODO: Lifting could be improved to remove some brackets. let expected = """ - const v1 = Math.random(); - print((4 * ((v1 + v1) + v1)) / 2); + const v1 = Math.random(); + print((4 * ((v1 + v1) + v1)) / 2); - """ + """ XCTAssertEqual(actual, expected) } @@ -1277,19 +1279,19 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let v0 = b.loadRegExp("a", RegExpFlags()) - b.compare(v0, with: v0, using: .equal); + b.compare(v0, with: v0, using: .equal) let v1 = b.loadRegExp("b", RegExpFlags()) - b.compare(v0, with: v1, using: .equal); + b.compare(v0, with: v1, using: .equal) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = /a/; - v0 == v0; - v0 == /b/; + const v0 = /a/; + v0 == v0; + v0 == /b/; - """ + """ XCTAssertEqual(actual, expected) } @@ -1298,15 +1300,15 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let code1 = b.buildCodeString() { - let code2 = b.buildCodeString() { - let code3 = b.buildCodeString() { - let code4 = b.buildCodeString() { + let code1 = b.buildCodeString { + let code2 = b.buildCodeString { + let code3 = b.buildCodeString { + let code4 = b.buildCodeString { let print = b.createNamedVariable(forBuiltin: "print") let msg = b.loadString("Hello") b.callFunction(print, withArgs: [msg]) } - let code5 = b.buildCodeString() { + let code5 = b.buildCodeString { let print = b.createNamedVariable(forBuiltin: "print") let msg = b.loadString("World") b.callFunction(print, withArgs: [msg]) @@ -1328,25 +1330,25 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = ` - const v1 = \\` - const v2 = \\\\\\` - const v3 = \\\\\\\\\\\\\\` - print("Hello"); - \\\\\\\\\\\\\\`; - const v7 = \\\\\\\\\\\\\\` - print("World"); - \\\\\\\\\\\\\\`; - eval(v3); - eval(v7); - \\\\\\`; - eval(v2); - \\`; - eval(v1); - `; - eval(v0); - - """ + const v0 = ` + const v1 = \\` + const v2 = \\\\\\` + const v3 = \\\\\\\\\\\\\\` + print("Hello"); + \\\\\\\\\\\\\\`; + const v7 = \\\\\\\\\\\\\\` + print("World"); + \\\\\\\\\\\\\\`; + eval(v3); + eval(v7); + \\\\\\`; + eval(v2); + \\`; + eval(v1); + `; + eval(v0); + + """ XCTAssertEqual(actual, expected) @@ -1370,14 +1372,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - return a1; - } - f0(13.37); - f0 = () => "foobar"; - f0(); + function f0(a1) { + return a1; + } + f0(13.37); + f0 = () => "foobar"; + f0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1388,13 +1390,16 @@ class LifterTests: XCTestCase { let sf = b.buildPlainFunction(with: .parameters(n: 3)) { args in b.directive("use strict") - b.buildIfElse(args[0], ifBody: { - let v = b.binary(args[1], args[2], with: .Mul) - b.doReturn(v) - }, elseBody: { - let v = b.binary(args[1], args[2], with: .Add) - b.doReturn(v) - }) + b.buildIfElse( + args[0], + ifBody: { + let v = b.binary(args[1], args[2], with: .Mul) + b.doReturn(v) + }, + elseBody: { + let v = b.binary(args[1], args[2], with: .Add) + b.doReturn(v) + }) } b.callFunction(sf, withArgs: [b.loadBool(true), b.loadInt(1), b.loadInt(2)]) @@ -1402,17 +1407,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2, a3) { - 'use strict'; - if (a1) { - return a2 * a3; - } else { - return a2 + a3; + function f0(a1, a2, a3) { + 'use strict'; + if (a1) { + return a2 * a3; + } else { + return a2 + a3; + } } - } - f0(true, 1, 2); + f0(true, 1, 2); - """ + """ XCTAssertEqual(actual, expected) } @@ -1435,20 +1440,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function foo() { - } - function* bar() { - } - async function baz() { - } - async function* bla() { - } - foo(); - bar(); - baz(); - bla(); + function foo() { + } + function* bar() { + } + async function baz() { + } + async function* bla() { + } + foo(); + bar(); + baz(); + bla(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1464,11 +1469,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - foo(); - function foo() { - } + foo(); + function foo() { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -1490,16 +1495,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function F0(a2, a3) { - if (!new.target) { throw 'must be called with new'; } - this.foo = a2; - this.bar = a3; - } - new F0(42, 43); - F0 = Object; - new F0(44, 45); + function F0(a2, a3) { + if (!new.target) { throw 'must be called with new'; } + this.foo = a2; + this.bar = a3; + } + new F0(42, 43); + F0 = Object; + new F0(44, 45); - """ + """ XCTAssertEqual(actual, expected) } @@ -1520,24 +1525,34 @@ class LifterTests: XCTestCase { let r = b.binary(lhs, rhs, with: .Mul) b.yield(r) } - b.callFunction(f1, withArgs: [b.createNamedVariable(forBuiltin: "promise1"), b.createNamedVariable(forBuiltin: "promise2")]) - b.callFunction(f2, withArgs: [b.createNamedVariable(forBuiltin: "promise3"), b.createNamedVariable(forBuiltin: "promise4")]) + b.callFunction( + f1, + withArgs: [ + b.createNamedVariable(forBuiltin: "promise1"), + b.createNamedVariable(forBuiltin: "promise2"), + ]) + b.callFunction( + f2, + withArgs: [ + b.createNamedVariable(forBuiltin: "promise3"), + b.createNamedVariable(forBuiltin: "promise4"), + ]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - async function f0(a1, a2) { - return await a1 + await a2; - } - async function* f6(a7, a8) { - 'use strict'; - yield await a7 * await a8; - } - f0(promise1, promise2); - f6(promise3, promise4); + async function f0(a1, a2) { + return await a1 + await a2; + } + async function* f6(a7, a8) { + 'use strict'; + yield await a7 * await a8; + } + f0(promise1, promise2); + f6(promise3, promise4); - """ + """ XCTAssertEqual(actual, expected) } @@ -1546,7 +1561,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let v1 = b.createObject(with: ["a" : b.loadInt(1337)]) + let v1 = b.createObject(with: ["a": b.loadInt(1337)]) let v2 = b.getProperty("a", of: v1) let v3 = b.loadInt(10) let v4 = b.compare(v2, with: v3, using: .greaterThan) @@ -1556,10 +1571,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = ({ a: 1337 }).a; - v2 > 10 ? v2 : 10; + const v2 = ({ a: 1337 }).a; + v2 > 10 ? v2 : 10; - """ + """ XCTAssertEqual(actual, expected) } @@ -1580,15 +1595,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 1337; - let v1 = 13.37; - v0 += v1; - v1 = "Hello"; - let v3 = 1336; - let v4 = ++v3; - v4++; + let v0 = 1337; + let v1 = 13.37; + v0 += v1; + v1 = "Hello"; + let v3 = 1336; + let v4 = ++v3; + v4++; - """ + """ XCTAssertEqual(actual, expected) } @@ -1610,14 +1625,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 1337; - v0 += 13.37; - v0 *= 13.37; - v0 <<= 13.37; - let v2 = "hello"; - v2 += "world"; + let v0 = 1337; + v0 += 13.37; + v0 *= 13.37; + v0 <<= 13.37; + let v2 = "hello"; + v2 += "world"; - """ + """ XCTAssertEqual(actual, expected) } @@ -1661,7 +1676,10 @@ class LifterTests: XCTestCase { b.setElement(42, of: n, to: n) let o = b.loadInt(53) - b.buildWhileLoop({ b.reassign(variable: o, value: i); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.reassign(variable: o, value: i) + return b.loadBool(false) + }) { } b.callFunction(foo, withArgs: [o]) @@ -1669,31 +1687,31 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v3 = 42; - foo(v3 = 43); - bar(v3); - let v7 = 44; - v7 = 45; - v7 = 46; - foo(v7); - let v11 = 47; - for (let v12 = 0; v12 < 10; v12++) { - v11 = v12; - } - foo(v11); - let v14 = 48; - foo(v14 = 49, v14, v14); - let v17 = 50; - foo(bar(v17 = 51, v17, baz(), v17)); - let v22 = 52; - v22 = []; - v22[42] = v22; - let v24 = 53; - while (v24 = v3, false) { - } - foo(v24); + let v3 = 42; + foo(v3 = 43); + bar(v3); + let v7 = 44; + v7 = 45; + v7 = 46; + foo(v7); + let v11 = 47; + for (let v12 = 0; v12 < 10; v12++) { + v11 = v12; + } + foo(v11); + let v14 = 48; + foo(v14 = 49, v14, v14); + let v17 = 50; + foo(bar(v17 = 51, v17, baz(), v17)); + let v22 = 52; + v22 = []; + v22[42] = v22; + let v24 = 53; + while (v24 = v3, false) { + } + foo(v24); - """ + """ XCTAssertEqual(actual, expected) } @@ -1708,18 +1726,19 @@ class LifterTests: XCTestCase { let marker = b.callFunction(b.createNamedVariable(forBuiltin: "getMarker")) let space = b.loadString(" ") let inner = b.createTemplateString(from: ["Hello", "World"], interpolating: [space]) - let _ = b.createTemplateString(from: ["", "", "", ""], interpolating: [marker, inner, marker] ) + let _ = b.createTemplateString( + from: ["", "", "", ""], interpolating: [marker, inner, marker]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - ``; - `foo${"bar"}baz`; - const v4 = getMarker(); - `${v4}${`Hello${" "}World`}${v4}`; + ``; + `foo${"bar"}baz`; + const v4 = getMarker(); + `${v4}${`Hello${" "}World`}${v4}`; - """ + """ XCTAssertEqual(actual, expected) } @@ -1744,11 +1763,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Obj[1337] = Obj.a.b.c; - const t1 = []; - t1[Obj[0][1][2]] = 42; + Obj[1337] = Obj.a.b.c; + const t1 = []; + t1[Obj[0][1][2]] = 42; - """ + """ XCTAssertEqual(actual, expected) } @@ -1759,7 +1778,7 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(42) let v1 = b.createObject(with: ["foo": v0]) - let v2 = b.loadString("baz") + let v2 = b.loadString("baz") let v3 = b.loadInt(1337) let v4 = b.loadString("42") let v5 = b.loadFloat(13.37) @@ -1769,7 +1788,7 @@ class LifterTests: XCTestCase { b.updateProperty("bar", of: v1, with: v3, using: BinaryOperator.Mul) b.setComputedProperty(v2, of: v1, to: v0) b.updateComputedProperty(v2, of: v1, with: v3, using: BinaryOperator.LogicAnd) - let arr = b.createArray(with: [v3,v3,v3]) + let arr = b.createArray(with: [v3, v3, v3]) b.setElement(0, of: arr, to: v0) b.updateElement(0, of: arr, with: v5, using: BinaryOperator.Sub) @@ -1777,18 +1796,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { foo: 42 }; - v1.foo = 13.37; - v1.foo += "42"; - v1.bar = 1337; - v1.bar *= 1337; - v1["baz"] = 42; - v1["baz"] &&= 1337; - const v6 = [1337,1337,1337]; - v6[0] = 42; - v6[0] -= 13.37; - - """ + const v1 = { foo: 42 }; + v1.foo = 13.37; + v1.foo += "42"; + v1.bar = 1337; + v1.bar *= 1337; + v1["baz"] = 42; + v1["baz"] &&= 1337; + const v6 = [1337,1337,1337]; + v6[0] = 42; + v6[0] -= 13.37; + + """ XCTAssertEqual(actual, expected) } @@ -1806,13 +1825,16 @@ class LifterTests: XCTestCase { b.reassign(variable: v, value: args[0]) } let num = b.loadInt(42) - b.configureProperty("foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) + b.configureProperty( + "foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) b.configureProperty("bar", of: obj, usingFlags: [], as: .setter(f2)) b.configureProperty("foobar", of: obj, usingFlags: [.enumerable], as: .getterSetter(f1, f2)) b.configureProperty("baz", of: obj, usingFlags: [.writable], as: .value(num)) b.configureElement(0, of: obj, usingFlags: [.writable], as: .getter(f1)) b.configureElement(1, of: obj, usingFlags: [.writable, .enumerable], as: .setter(f2)) - b.configureElement(2, of: obj, usingFlags: [.writable, .enumerable, .configurable], as: .getterSetter(f1, f2)) + b.configureElement( + 2, of: obj, usingFlags: [.writable, .enumerable, .configurable], + as: .getterSetter(f1, f2)) b.configureElement(3, of: obj, usingFlags: [], as: .value(num)) let p = b.createNamedVariable(forBuiltin: "ComputedProperty") b.configureComputedProperty(p, of: obj, usingFlags: [.configurable], as: .getter(f1)) @@ -1824,28 +1846,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - let v1 = undefined; - function f2() { - return v1; - } - function f3(a4) { - v1 = a4; - } - Object.defineProperty(v0, "foo", { configurable: true, enumerable: true, get: f2 }); - Object.defineProperty(v0, "bar", { set: f3 }); - Object.defineProperty(v0, "foobar", { enumerable: true, get: f2, set: f3 }); - Object.defineProperty(v0, "baz", { writable: true, value: 42 }); - Object.defineProperty(v0, 0, { writable: true, get: f2 }); - Object.defineProperty(v0, 1, { writable: true, enumerable: true, set: f3 }); - Object.defineProperty(v0, 2, { writable: true, configurable: true, enumerable: true, get: f2, set: f3 }); - Object.defineProperty(v0, 3, { value: 42 }); - Object.defineProperty(v0, ComputedProperty, { configurable: true, get: f2 }); - Object.defineProperty(v0, ComputedProperty, { enumerable: true, set: f3 }); - Object.defineProperty(v0, ComputedProperty, { writable: true, get: f2, set: f3 }); - Object.defineProperty(v0, ComputedProperty, { value: 42 }); - - """ + const v0 = {}; + let v1 = undefined; + function f2() { + return v1; + } + function f3(a4) { + v1 = a4; + } + Object.defineProperty(v0, "foo", { configurable: true, enumerable: true, get: f2 }); + Object.defineProperty(v0, "bar", { set: f3 }); + Object.defineProperty(v0, "foobar", { enumerable: true, get: f2, set: f3 }); + Object.defineProperty(v0, "baz", { writable: true, value: 42 }); + Object.defineProperty(v0, 0, { writable: true, get: f2 }); + Object.defineProperty(v0, 1, { writable: true, enumerable: true, set: f3 }); + Object.defineProperty(v0, 2, { writable: true, configurable: true, enumerable: true, get: f2, set: f3 }); + Object.defineProperty(v0, 3, { value: 42 }); + Object.defineProperty(v0, ComputedProperty, { configurable: true, get: f2 }); + Object.defineProperty(v0, ComputedProperty, { enumerable: true, set: f3 }); + Object.defineProperty(v0, ComputedProperty, { writable: true, get: f2, set: f3 }); + Object.defineProperty(v0, ComputedProperty, { value: 42 }); + + """ XCTAssertEqual(actual, expected) } @@ -1870,13 +1892,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v3 = { bar: 13.37, foo: 1337 }; - delete v3.foo; - delete v3["bar"]; - const t1 = [301,4,68,22]; - delete t1[3]; + const v3 = { bar: 13.37, foo: 1337 }; + delete v3.foo; + delete v3["bar"]; + const t1 = [301,4,68,22]; + delete t1[3]; - """ + """ XCTAssertEqual(actual, expected) } @@ -1907,20 +1929,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - o?.a?.b; - o?.[0]; - o?.["bar"]; - delete o?.unfoo; - delete o?.[1]; - delete o?.["unbar"]; - const t0 = o?.t1; - t0.foo = 42; - const t8 = o?.t2; - t8[0] = 42; - const t10 = o?.t3; - t10["baz"] = 42; - - """ + o?.a?.b; + o?.[0]; + o?.["bar"]; + delete o?.unfoo; + delete o?.[1]; + delete o?.["unbar"]; + const t0 = o?.t1; + t0.foo = 42; + const t8 = o?.t2; + t8[0] = 42; + const t10 = o?.t3; + t10["baz"] = 42; + + """ XCTAssertEqual(actual, expected) } @@ -1941,7 +1963,8 @@ class LifterTests: XCTestCase { b.callMethod("m", on: o, guard: true) let v3 = b.callMethod("n", on: o, guard: true) b.callComputedMethod(b.loadString("o"), on: o, withArgs: [v1, v2, v3], guard: true) - let v4 = b.callComputedMethod(b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) + let v4 = b.callComputedMethod( + b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) b.reassign(variable: v3, value: b.loadString("foo")) b.reassign(variable: v4, value: b.loadString("bar")) b.reassign(variable: v3, value: b.loadString("baz")) @@ -1950,23 +1973,23 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - try { f1(); } catch (e) {} - let v3; - try { v3 = f2(); } catch (e) {} - try { new c1(); } catch (e) {} - let v7; - try { v7 = new c2(); } catch (e) {} - try { obj.m(); } catch (e) {} - let v10; - try { v10 = obj.n(); } catch (e) {} - try { obj["o"](v3, v7, v10); } catch (e) {} - let v14; - try { v14 = obj["p"](v3, v7, v10); } catch (e) {} - v10 = "foo"; - v14 = "bar"; - v10 = "baz"; - - """ + try { f1(); } catch (e) {} + let v3; + try { v3 = f2(); } catch (e) {} + try { new c1(); } catch (e) {} + let v7; + try { v7 = new c2(); } catch (e) {} + try { obj.m(); } catch (e) {} + let v10; + try { v10 = obj.n(); } catch (e) {} + try { obj["o"](v3, v7, v10); } catch (e) {} + let v14; + try { v14 = obj["p"](v3, v7, v10); } catch (e) {} + v10 = "foo"; + v14 = "bar"; + v10 = "baz"; + + """ XCTAssertEqual(actual, expected) } @@ -1982,12 +2005,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - try { - const t0 = "foo"; - new t0(); - } catch (e) {} + try { + const t0 = "foo"; + new t0(); + } catch (e) {} - """ + """ XCTAssertEqual(actual, expected) } @@ -2009,12 +2032,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - eval("print('Hello World!')"); - const t0 = this.eval; - t0("print('Hello World!')"); - this.eval("print('Hello World!')"); + eval("print('Hello World!')"); + const t0 = this.eval; + t0("print('Hello World!')"); + this.eval("print('Hello World!')"); - """ + """ XCTAssertEqual(actual, expected) } @@ -2031,15 +2054,15 @@ class LifterTests: XCTestCase { let values = b.createArray(with: initialValues) let n = b.loadFloat(13.37) let Array = b.createNamedVariable(forBuiltin: "Array") - let _ = b.callFunction(Array, withArgs: [values,n], spreading: [true,false]) + let _ = b.callFunction(Array, withArgs: [values, n], spreading: [true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - Array(...[1,2,"Hello","World"], 13.37); + Array(...[1,2,"Hello","World"], 13.37); - """ + """ XCTAssertEqual(actual, expected) } @@ -2056,9 +2079,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Math.sin(Math.random()); + Math.sin(Math.random()); - """ + """ XCTAssertEqual(actual, expected) } @@ -2076,11 +2099,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = Math.random(); - let v2 = Function.prototype.call.bind(Math.sin); - v2(Math, v1); + const v1 = Math.random(); + let v2 = Function.prototype.call.bind(Math.sin); + v2(Math, v1); - """ + """ XCTAssertEqual(actual, expected) } @@ -2112,15 +2135,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = Array.prototype.indexOf; - let v3 = v2.bind(); - const v4 = new Array(); - let v5 = v2.bind(v4); - let v7 = v2.bind(v4, "value"); - let v9 = v2.bind(v4, "value", 1); - let v10 = v2.bind(v4, "value", 1, 1); + const v2 = Array.prototype.indexOf; + let v3 = v2.bind(); + const v4 = new Array(); + let v5 = v2.bind(v4); + let v7 = v2.bind(v4, "value"); + let v9 = v2.bind(v4, "value", 1); + let v10 = v2.bind(v4, "value", 1, 1); - """ + """ XCTAssertEqual(actual, expected) } @@ -2140,15 +2163,15 @@ class LifterTests: XCTestCase { let values = b.createArray(with: initialValues) let n1 = b.loadInt(0) let n2 = b.loadInt(4) - b.callMethod("max", on: Math, withArgs: [n1,values,n2], spreading: [false, true, false]) + b.callMethod("max", on: Math, withArgs: [n1, values, n2], spreading: [false, true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - Math.max(0, ...[1,3,9,10,2,6], 4); + Math.max(0, ...[1,3,9,10,2,6], 4); - """ + """ XCTAssertEqual(actual, expected) } @@ -2166,9 +2189,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - ("Hello World")[Symbol.iterator]().next(); + ("Hello World")[Symbol.iterator]().next(); - """ + """ XCTAssertEqual(actual, expected) } @@ -2178,7 +2201,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj) } @@ -2186,17 +2209,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0["???"](); - v0[0](); - v0["01"](); - v0[1](); - v0["0.1"](); - v0["-1"](); - v0.$valid_id_42(); - v0["42_invalid_id"](); - - """ + const v0 = {}; + v0["???"](); + v0[0](); + v0["01"](); + v0[1](); + v0["0.1"](); + v0["-1"](); + v0.$valid_id_42(); + v0["42_invalid_id"](); + + """ XCTAssertEqual(actual, expected) } @@ -2207,7 +2230,7 @@ class LifterTests: XCTestCase { let obj = b.createObject(with: [:]) let values = b.createArray(with: []) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj, withArgs: [values], spreading: [true]) } @@ -2215,18 +2238,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - const v1 = []; - v0["???"](...v1); - v0[0](...v1); - v0["01"](...v1); - v0[1](...v1); - v0["0.1"](...v1); - v0["-1"](...v1); - v0.$valid_id_42(...v1); - v0["42_invalid_id"](...v1); - - """ + const v0 = {}; + const v1 = []; + v0["???"](...v1); + v0[0](...v1); + v0["01"](...v1); + v0[1](...v1); + v0["0.1"](...v1); + v0["-1"](...v1); + v0.$valid_id_42(...v1); + v0["42_invalid_id"](...v1); + + """ XCTAssertEqual(actual, expected) } @@ -2236,7 +2259,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { let bound = b.bindMethod(name, on: obj) b.callFunction(bound, withArgs: [obj]) } @@ -2245,25 +2268,25 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - let v1 = Function.prototype.call.bind(v0["???"]); - v1(v0); - let v3 = Function.prototype.call.bind(v0[0]); - v3(v0); - let v5 = Function.prototype.call.bind(v0["01"]); - v5(v0); - let v7 = Function.prototype.call.bind(v0[1]); - v7(v0); - let v9 = Function.prototype.call.bind(v0["0.1"]); - v9(v0); - let v11 = Function.prototype.call.bind(v0["-1"]); - v11(v0); - let v13 = Function.prototype.call.bind(v0.$valid_id_42); - v13(v0); - let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); - v15(v0); - - """ + const v0 = {}; + let v1 = Function.prototype.call.bind(v0["???"]); + v1(v0); + let v3 = Function.prototype.call.bind(v0[0]); + v3(v0); + let v5 = Function.prototype.call.bind(v0["01"]); + v5(v0); + let v7 = Function.prototype.call.bind(v0[1]); + v7(v0); + let v9 = Function.prototype.call.bind(v0["0.1"]); + v9(v0); + let v11 = Function.prototype.call.bind(v0["-1"]); + v11(v0); + let v13 = Function.prototype.call.bind(v0.$valid_id_42); + v13(v0); + let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); + v15(v0); + + """ XCTAssertEqual(actual, expected) } @@ -2272,9 +2295,9 @@ class LifterTests: XCTestCase { let fuzzer: Fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callSuperMethod(name) } } @@ -2284,20 +2307,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - sub() { - super["???"](); - super[0](); - super["01"](); - super[1](); - super["0.1"](); - super["-1"](); - super.$valid_id_42(); - super["42_invalid_id"](); + class C0 { + sub() { + super["???"](); + super[0](); + super["01"](); + super[1](); + super["0.1"](); + super["-1"](); + super.$valid_id_42(); + super["42_invalid_id"](); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -2316,9 +2339,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - SomeObject[RandomMethod()](...[1,2,3,4]); + SomeObject[RandomMethod()](...[1,2,3,4]); - """ + """ XCTAssertEqual(actual, expected) } @@ -2328,9 +2351,10 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.setProperty(name, of: obj, to: b.getProperty(name, of: obj)) - b.updateProperty(name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) + b.updateProperty( + name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) b.deleteProperty(name, of: obj) } @@ -2338,33 +2362,33 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0["???"] = v0["???"]; - v0["???"] += v0?.["???"]; - delete v0["???"]; - v0[0] = v0[0]; - v0[0] += v0?.[0]; - delete v0[0]; - v0["01"] = v0["01"]; - v0["01"] += v0?.["01"]; - delete v0["01"]; - v0[1] = v0[1]; - v0[1] += v0?.[1]; - delete v0[1]; - v0["0.1"] = v0["0.1"]; - v0["0.1"] += v0?.["0.1"]; - delete v0["0.1"]; - v0["-1"] = v0["-1"]; - v0["-1"] += v0?.["-1"]; - delete v0["-1"]; - v0.$valid_id_42 = v0.$valid_id_42; - v0.$valid_id_42 += v0?.$valid_id_42; - delete v0.$valid_id_42; - v0["42_invalid_id"] = v0["42_invalid_id"]; - v0["42_invalid_id"] += v0?.["42_invalid_id"]; - delete v0["42_invalid_id"]; - - """ + const v0 = {}; + v0["???"] = v0["???"]; + v0["???"] += v0?.["???"]; + delete v0["???"]; + v0[0] = v0[0]; + v0[0] += v0?.[0]; + delete v0[0]; + v0["01"] = v0["01"]; + v0["01"] += v0?.["01"]; + delete v0["01"]; + v0[1] = v0[1]; + v0[1] += v0?.[1]; + delete v0[1]; + v0["0.1"] = v0["0.1"]; + v0["0.1"] += v0?.["0.1"]; + delete v0["0.1"]; + v0["-1"] = v0["-1"]; + v0["-1"] += v0?.["-1"]; + delete v0["-1"]; + v0.$valid_id_42 = v0.$valid_id_42; + v0.$valid_id_42 += v0?.$valid_id_42; + delete v0.$valid_id_42; + v0["42_invalid_id"] = v0["42_invalid_id"]; + v0["42_invalid_id"] += v0?.["42_invalid_id"]; + delete v0["42_invalid_id"]; + + """ XCTAssertEqual(actual, expected) } @@ -2373,9 +2397,9 @@ class LifterTests: XCTestCase { let fuzzer: Fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.setSuperProperty(name, to: b.getSuperProperty(name)) b.updateSuperProperty(name, with: b.getSuperProperty(name), using: .Add) } @@ -2386,28 +2410,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - sub() { - super["???"] = super["???"]; - super["???"] += super["???"]; - super[0] = super[0]; - super[0] += super[0]; - super["01"] = super["01"]; - super["01"] += super["01"]; - super[1] = super[1]; - super[1] += super[1]; - super["0.1"] = super["0.1"]; - super["0.1"] += super["0.1"]; - super["-1"] = super["-1"]; - super["-1"] += super["-1"]; - super.$valid_id_42 = super.$valid_id_42; - super.$valid_id_42 += super.$valid_id_42; - super["42_invalid_id"] = super["42_invalid_id"]; - super["42_invalid_id"] += super["42_invalid_id"]; + class C0 { + sub() { + super["???"] = super["???"]; + super["???"] += super["???"]; + super[0] = super[0]; + super[0] += super[0]; + super["01"] = super["01"]; + super["01"] += super["01"]; + super[1] = super[1]; + super[1] += super[1]; + super["0.1"] = super["0.1"]; + super["0.1"] += super["0.1"]; + super["-1"] = super["-1"]; + super["-1"] += super["-1"]; + super.$valid_id_42 = super.$valid_id_42; + super.$valid_id_42 += super.$valid_id_42; + super["42_invalid_id"] = super["42_invalid_id"]; + super["42_invalid_id"] += super["42_invalid_id"]; + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -2425,15 +2449,15 @@ class LifterTests: XCTestCase { let n1 = b.loadFloat(13.37) let n2 = b.loadFloat(13.38) let Array = b.createNamedVariable(forBuiltin: "Array") - b.construct(Array, withArgs: [n1,values,n2], spreading: [false,true,false]) + b.construct(Array, withArgs: [n1, values, n2], spreading: [false, true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - new Array(13.37, ...[1,2,"Hello","World"], 13.38); + new Array(13.37, ...[1,2,"Hello","World"], 13.38); - """ + """ XCTAssertEqual(actual, expected) } @@ -2442,7 +2466,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2468,28 +2492,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - } - f(a4) { - return "foobar"; - } - } - class C6 extends C0 { - constructor(a8) { - super(); - super.bar = 100; - } - g(a11) { - super.bar += 1337; + class C0 { + constructor(a2) { + } + f(a4) { + return "foobar"; + } } - h() { - return super.bar; + class C6 extends C0 { + constructor(a8) { + super(); + super.bar = 100; + } + g(a11) { + super.bar += 1337; + } + h() { + return super.bar; + } } - } - new C6(13.37); + new C6(13.37); - """ + """ XCTAssertEqual(actual, expected) } @@ -2498,7 +2522,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2513,13 +2537,13 @@ class LifterTests: XCTestCase { let C = b.buildClassDefinition(withSuperclass: superclass) { cls in cls.addConstructor(with: .parameters(n: 1)) { params in - b.callSuperConstructor(withArgs: []); + b.callSuperConstructor(withArgs: []) b.setComputedSuperProperty(params[1], to: b.loadInt(100)) } cls.addInstanceMethod("g", with: .parameters(n: 1)) { params in let property = b.binary(b.callFunction(function), params[1], with: .Add) b.doReturn(b.getComputedSuperProperty(property)) - } + } } b.construct(C, withArgs: [b.loadFloat(13.37)]) @@ -2527,28 +2551,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - } - f(a4) { - return "foobar"; + class C0 { + constructor(a2) { + } + f(a4) { + return "foobar"; + } } - } - function f6() { - return "baz"; - } - class C8 extends C0 { - constructor(a10) { - super(); - super[a10] = 100; + function f6() { + return "baz"; } - g(a13) { - return super[f6() + a13]; + class C8 extends C0 { + constructor(a10) { + super(); + super[a10] = 100; + } + g(a13) { + return super[f6() + a13]; + } } - } - new C8(13.37); + new C8(13.37); - """ + """ XCTAssertEqual(actual, expected) @@ -2570,13 +2594,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = { bar: 13.37, foo: 42 }; - let {"foo":v3,...v4} = v2; - let {"foo":v5,"bar":v6,...v7} = v2; - let {...v8} = v2; - let {"foo":v9,"bar":v10,} = v2; + const v2 = { bar: 13.37, foo: 42 }; + let {"foo":v3,...v4} = v2; + let {"foo":v5,"bar":v6,...v7} = v2; + let {...v8} = v2; + let {"foo":v9,"bar":v10,} = v2; - """ + """ XCTAssertEqual(actual, expected) } @@ -2589,27 +2613,27 @@ class LifterTests: XCTestCase { let v1 = b.loadFloat(13.37) let v2 = b.loadString("Hello") let v3 = b.createObject(with: ["foo": v0, "bar": v1]) - b.destruct(v3, selecting: ["foo"], into: [v2,v0], hasRestElement: true) - b.destruct(v3, selecting: ["foo", "bar"], into: [v2,v0,v1], hasRestElement: true) + b.destruct(v3, selecting: ["foo"], into: [v2, v0], hasRestElement: true) + b.destruct(v3, selecting: ["foo", "bar"], into: [v2, v0, v1], hasRestElement: true) b.destruct(v3, selecting: [String](), into: [v2], hasRestElement: true) - b.destruct(v3, selecting: ["foo", "bar"], into: [v2,v1]) + b.destruct(v3, selecting: ["foo", "bar"], into: [v2, v1]) b.destruct(v3, selecting: [String](), into: []) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 42; - let v1 = 13.37; - let v2 = "Hello"; - const v3 = { bar: v1, foo: v0 }; - ({"foo":v2,...v0} = v3); - ({"foo":v2,"bar":v0,...v1} = v3); - ({...v2} = v3); - ({"foo":v2,"bar":v1,} = v3); - ({} = v3); - - """ + let v0 = 42; + let v1 = 13.37; + let v2 = "Hello"; + const v3 = { bar: v1, foo: v0 }; + ({"foo":v2,...v0} = v3); + ({"foo":v2,"bar":v0,...v1} = v3); + ({...v2} = v3); + ({"foo":v2,"bar":v1,} = v3); + ({} = v3); + + """ XCTAssertEqual(actual, expected) } @@ -2624,22 +2648,22 @@ class LifterTests: XCTestCase { initialValues.append(b.loadString("Hello")) initialValues.append(b.loadString("World")) let arr = b.createArray(with: initialValues) - b.destruct(arr, selecting: [0,1]) - b.destruct(arr, selecting: [0,2,5]) - b.destruct(arr, selecting: [0,2], lastIsRest: true) + b.destruct(arr, selecting: [0, 1]) + b.destruct(arr, selecting: [0, 2, 5]) + b.destruct(arr, selecting: [0, 2], lastIsRest: true) b.destruct(arr, selecting: [0], lastIsRest: true) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = [15,30,"Hello","World"]; - let [v5,v6] = v4; - let [v7,,v8,,,v9] = v4; - let [v10,,...v11] = v4; - let [...v12] = v4; + const v4 = [15,30,"Hello","World"]; + let [v5,v6] = v4; + let [v7,,v8,,,v9] = v4; + let [v10,,...v11] = v4; + let [...v12] = v4; - """ + """ XCTAssertEqual(actual, expected) } @@ -2656,20 +2680,20 @@ class LifterTests: XCTestCase { let array = b.createArray(with: initialValues) let i = b.loadInt(1000) let s = b.loadString("foobar") - b.destruct(array, selecting: [0,2], into: [i, s], lastIsRest: true) + b.destruct(array, selecting: [0, 2], into: [i, s], lastIsRest: true) b.destruct(array, selecting: [0], into: [i], lastIsRest: true) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = [15,30,"Hello","World"]; - let v5 = 1000; - let v6 = "foobar"; - [v5,,...v6] = v4; - [...v5] = v4; + const v4 = [15,30,"Hello","World"]; + let v5 = 1000; + let v6 = "foobar"; + [v5,,...v6] = v4; + [...v5] = v4; - """ + """ XCTAssertEqual(actual, expected) } @@ -2698,17 +2722,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let a = 42; - print(a); - print(b); - c = 1337; - var b = 1337; - b = 42; - print(c); - let d; - print(d); - - """ + let a = 42; + print(a); + print(b); + c = 1337; + var b = 1337; + b = 42; + print(c); + let d; + print(d); + + """ XCTAssertEqual(actual, expected) } @@ -2718,13 +2742,15 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, catchBody: { _ in - let v = b.binary(args[0], args[1], with: .Div) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + catchBody: { _ in + let v = b.binary(args[0], args[1], with: .Div) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2732,16 +2758,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } catch(e4) { - return a1 / a2; + function f0(a1, a2) { + try { + return a1 * a2; + } catch(e4) { + return a1 / a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2751,13 +2777,15 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, finallyBody: { - let v = b.binary(args[0], args[1], with: .Mod) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + finallyBody: { + let v = b.binary(args[0], args[1], with: .Mod) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2765,16 +2793,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } finally { - return a1 % a2; + function f0(a1, a2) { + try { + return a1 * a2; + } finally { + return a1 % a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2784,16 +2812,19 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, catchBody: { _ in - let v = b.binary(args[0], args[1], with: .Div) - b.doReturn(v) - }, finallyBody: { - let v = b.binary(args[0], args[1], with: .Mod) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + catchBody: { _ in + let v = b.binary(args[0], args[1], with: .Div) + b.doReturn(v) + }, + finallyBody: { + let v = b.binary(args[0], args[1], with: .Mod) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2801,18 +2832,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } catch(e4) { - return a1 / a2; - } finally { - return a1 % a2; + function f0(a1, a2) { + try { + return a1 * a2; + } catch(e4) { + return a1 / a2; + } finally { + return a1 % a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2823,7 +2854,7 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(42) let v1 = b.createObject(with: ["foo": v0]) - let v2 = b.getProperty("foo", of: v1) + let v2 = b.getProperty("foo", of: v1) let v3 = b.loadInt(1337) let v4 = b.loadString("42") let v5 = b.loadFloat(13.37) @@ -2832,10 +2863,10 @@ class LifterTests: XCTestCase { swtch.addCase(v3, fallsThrough: false) { b.setProperty("bar", of: v1, to: v3) } - swtch.addCase(v4, fallsThrough: false){ + swtch.addCase(v4, fallsThrough: false) { b.setProperty("baz", of: v1, to: v4) } - swtch.addDefaultCase(fallsThrough: true){ + swtch.addDefaultCase(fallsThrough: true) { b.setProperty("foo", of: v1, to: v5) } swtch.addCase(v0, fallsThrough: true) { @@ -2847,22 +2878,22 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { foo: 42 }; - const v2 = v1.foo; - switch (v2) { - case 1337: - v1.bar = 1337; - break; - case "42": - v1.baz = "42"; - break; - default: - v1.foo = 13.37; - case 42: - v1.bla = v2; - } + const v1 = { foo: 42 }; + const v2 = v1.foo; + switch (v2) { + case 1337: + v1.bar = 1337; + break; + case "42": + v1.baz = "42"; + break; + default: + v1.foo = 13.37; + case 42: + v1.bla = v2; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2880,12 +2911,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - while (v0 < 100) { - v0++; - } + let v0 = 0; + while (v0 < 100) { + v0++; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2903,10 +2934,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - while (shouldContinue()) { - } + while (shouldContinue()) { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2918,7 +2949,11 @@ class LifterTests: XCTestCase { let f = b.createNamedVariable(forBuiltin: "f") let g = b.createNamedVariable(forBuiltin: "g") let loopVar = b.loadInt(10) - b.buildWhileLoop({ b.callFunction(f); b.callFunction(g); return loopVar }) { + b.buildWhileLoop({ + b.callFunction(f) + b.callFunction(g) + return loopVar + }) { b.unary(.PostDec, loopVar) } @@ -2926,12 +2961,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v2 = 10; - while (f(), g(), v2) { - v2--; - } + let v2 = 10; + while (f(), g(), v2) { + v2--; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2942,23 +2977,31 @@ class LifterTests: XCTestCase { var f = b.createNamedVariable(forBuiltin: "f") var g = b.createNamedVariable(forBuiltin: "g") - b.buildWhileLoop({ b.callFunction(f); let cond = b.callFunction(g); return cond }) { + b.buildWhileLoop({ + b.callFunction(f) + let cond = b.callFunction(g) + return cond + }) { } var program = b.finalize() var actual = fuzzer.lifter.lift(program) var expected = """ - while (f(), g()) { - } + while (f(), g()) { + } - """ + """ XCTAssertEqual(actual, expected) f = b.createNamedVariable(forBuiltin: "f") g = b.createNamedVariable(forBuiltin: "g") - b.buildWhileLoop({ let cond = b.callFunction(f); b.callFunction(g); return cond }) { + b.buildWhileLoop({ + let cond = b.callFunction(f) + b.callFunction(g) + return cond + }) { b.callFunction(b.createNamedVariable(forBuiltin: "body")) } @@ -2966,15 +3009,15 @@ class LifterTests: XCTestCase { actual = fuzzer.lifter.lift(program) expected = """ - while ((() => { - const v2 = f(); - g(); - return v2; - })()) { - body(); - } + while ((() => { + const v2 = f(); + g(); + return v2; + })()) { + body(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2996,14 +3039,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - while ((() => { - const v1 = foobar(); - return v1 + v1; - })()) { - doLoopBodyStuff(); - } + while ((() => { + const v1 = foobar(); + return v1 + v1; + })()) { + doLoopBodyStuff(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3016,7 +3059,10 @@ class LifterTests: XCTestCase { let f = b.callFunction(b.createNamedVariable(forBuiltin: "f")) let g = b.callFunction(b.createNamedVariable(forBuiltin: "g")) let h = b.callFunction(b.createNamedVariable(forBuiltin: "h")) - b.buildWhileLoop({ b.callFunction(print, withArgs: [f]); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.callFunction(print, withArgs: [f]) + return b.loadBool(false) + }) { b.callFunction(print, withArgs: [g]) } b.callFunction(print, withArgs: [h]) @@ -3025,15 +3071,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - while (print(v2), false) { - print(v4); - } - print(v6); + const v2 = f(); + const v4 = g(); + const v6 = h(); + while (print(v2), false) { + print(v4); + } + print(v6); - """ + """ XCTAssertEqual(actual, expected) } @@ -3043,28 +3089,33 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let loopVar1 = b.loadInt(0) - b.buildDoWhileLoop(do: { - let loopVar2 = b.loadInt(0) - b.buildDoWhileLoop(do: { - b.unary(.PostInc, loopVar2) - }, while: { b.callFunction(b.createNamedVariable(forBuiltin: "f"), withArgs: [loopVar2]) }) - b.unary(.PostInc, loopVar1) - }, while: { b.compare(loopVar1, with: b.loadInt(42), using: .lessThan) }) + b.buildDoWhileLoop( + do: { + let loopVar2 = b.loadInt(0) + b.buildDoWhileLoop( + do: { + b.unary(.PostInc, loopVar2) + }, + while: { + b.callFunction(b.createNamedVariable(forBuiltin: "f"), withArgs: [loopVar2]) + }) + b.unary(.PostInc, loopVar1) + }, while: { b.compare(loopVar1, with: b.loadInt(42), using: .lessThan) }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - do { - let v1 = 0; + let v0 = 0; do { - v1++; - } while (f(v1)) - v0++; - } while (v0 < 42) + let v1 = 0; + do { + v1++; + } while (f(v1)) + v0++; + } while (v0 < 42) - """ + """ XCTAssertEqual(actual, expected) } @@ -3073,20 +3124,25 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildDoWhileLoop(do: { - let doSomething = b.createNamedVariable(forBuiltin: "doSomething") - b.callFunction(doSomething) - }, while: { b.callFunction(b.createNamedVariable(forBuiltin: "f")); return b.callFunction(b.createNamedVariable(forBuiltin: "g")) }) + b.buildDoWhileLoop( + do: { + let doSomething = b.createNamedVariable(forBuiltin: "doSomething") + b.callFunction(doSomething) + }, + while: { + b.callFunction(b.createNamedVariable(forBuiltin: "f")) + return b.callFunction(b.createNamedVariable(forBuiltin: "g")) + }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - do { - doSomething(); - } while (f(), g()) + do { + doSomething(); + } while (f(), g()) - """ + """ XCTAssertEqual(actual, expected) } @@ -3099,24 +3155,29 @@ class LifterTests: XCTestCase { let f = b.callFunction(b.createNamedVariable(forBuiltin: "f")) let g = b.callFunction(b.createNamedVariable(forBuiltin: "g")) let h = b.callFunction(b.createNamedVariable(forBuiltin: "h")) - b.buildDoWhileLoop(do: { - b.callFunction(print, withArgs: [f]) - }, while: { b.callFunction(print, withArgs: [g]); return b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + b.callFunction(print, withArgs: [f]) + }, + while: { + b.callFunction(print, withArgs: [g]) + return b.loadBool(false) + }) b.callFunction(print, withArgs: [h]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - do { - print(v2); - } while (print(v4), false) - print(v6); + const v2 = f(); + const v4 = g(); + const v6 = h(); + do { + print(v2); + } while (print(v4), false) + print(v6); - """ + """ XCTAssertEqual(actual, expected) } @@ -3125,8 +3186,14 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.loadInt(10), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in - b.buildForLoop(i: { b.loadInt(0) }, { j in b.compare(j, with: i, using: .lessThan) }, { j in b.unary(.PostInc, j) }) { j in + b.buildForLoop( + i: { b.loadInt(0) }, { i in b.compare(i, with: b.loadInt(10), using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in + b.buildForLoop( + i: { b.loadInt(0) }, { j in b.compare(j, with: i, using: .lessThan) }, + { j in b.unary(.PostInc, j) } + ) { j in let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [i, j]) } @@ -3136,13 +3203,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i1 = 0; i1 < 10; i1++) { - for (let i8 = 0; i8 < i1; i8++) { - print(i1, i8); + for (let i1 = 0; i1 < 10; i1++) { + for (let i8 = 0; i8 < i1; i8++) { + print(i1, i8); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3151,7 +3218,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop() { + b.buildForLoop { b.loopBreak() } @@ -3159,11 +3226,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (;;) { - break; - } + for (;;) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3172,9 +3239,22 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ return [b.callFunction(b.createNamedVariable(forBuiltin: "f1")), b.callFunction(b.createNamedVariable(forBuiltin: "f2"))] }, - { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f3"), withArgs: [vars[0]]); return b.callFunction(b.createNamedVariable(forBuiltin: "f4"), withArgs: [vars[1]]) }, - { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f5"), withArgs: [vars[1]]); b.callFunction(b.createNamedVariable(forBuiltin: "f6"), withArgs: [vars[0]]) }) { vars in + b.buildForLoop( + { + return [ + b.callFunction(b.createNamedVariable(forBuiltin: "f1")), + b.callFunction(b.createNamedVariable(forBuiltin: "f2")), + ] + }, + { vars in + b.callFunction(b.createNamedVariable(forBuiltin: "f3"), withArgs: [vars[0]]) + return b.callFunction(b.createNamedVariable(forBuiltin: "f4"), withArgs: [vars[1]]) + }, + { vars in + b.callFunction(b.createNamedVariable(forBuiltin: "f5"), withArgs: [vars[1]]) + b.callFunction(b.createNamedVariable(forBuiltin: "f6"), withArgs: [vars[0]]) + } + ) { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f7"), withArgs: vars) } @@ -3182,11 +3262,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i4 = f1(), i5 = f2(); f3(i4), f4(i5); f5(i5), f6(i4)) { - f7(i4, i5); - } + for (let i4 = f1(), i5 = f2(); f3(i4), f4(i5); f5(i5), f6(i4)) { + f7(i4, i5); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3194,9 +3274,16 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")); let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")); b.callFunction(b.createNamedVariable(forBuiltin: "h")); return [x, y] }, - { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, - { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) }) { vs in + b.buildForLoop( + { + let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")) + let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")) + b.callFunction(b.createNamedVariable(forBuiltin: "h")) + return [x, y] + }, + { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, + { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) } + ) { vs in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: vs) } @@ -3204,18 +3291,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let [i6, i7] = (() => { - const v1 = f(); - const v3 = g(); - h(); - return [v1, v3]; - })(); - i6 < i7; - i6 += i7) { - print(i6, i7); - } + for (let [i6, i7] = (() => { + const v1 = f(); + const v3 = g(); + h(); + return [v1, v3]; + })(); + i6 < i7; + i6 += i7) { + print(i6, i7); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3224,14 +3311,20 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ b.callFunction(b.createNamedVariable(forBuiltin: "foo")); b.callFunction(b.createNamedVariable(forBuiltin: "bar")) }, - { - let shouldContinue = b.callFunction(b.createNamedVariable(forBuiltin: "shouldContinue")) - b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { - b.reassign(variable: shouldContinue, value: b.loadBool(false)) - } - return shouldContinue - }) { + b.buildForLoop( + { + b.callFunction(b.createNamedVariable(forBuiltin: "foo")) + b.callFunction(b.createNamedVariable(forBuiltin: "bar")) + }, + { + let shouldContinue = b.callFunction( + b.createNamedVariable(forBuiltin: "shouldContinue")) + b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { + b.reassign(variable: shouldContinue, value: b.loadBool(false)) + } + return shouldContinue + } + ) { b.loopBreak() } @@ -3239,19 +3332,19 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (foo(), bar(); - (() => { - let v5 = shouldContinue(); - if (shouldNotContinue()) { - v5 = false; - } - return v5; - })(); - ) { - break; - } + for (foo(), bar(); + (() => { + let v5 = shouldContinue(); + if (shouldNotContinue()) { + v5 = false; + } + return v5; + })(); + ) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3260,7 +3353,10 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, + { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) } @@ -3268,11 +3364,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i1 = 0; i1 < 100; i1 += 10) { - print(i1); - } + for (let i1 = 0; i1 < 100; i1 += 10) { + print(i1); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3281,7 +3377,12 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.callFunction(b.createNamedVariable(forBuiltin: "f")); return b.callFunction(b.createNamedVariable(forBuiltin: "g")) }, {_ in b.loadBool(true) }, { _ in }) { i in + b.buildForLoop( + i: { + b.callFunction(b.createNamedVariable(forBuiltin: "f")) + return b.callFunction(b.createNamedVariable(forBuiltin: "g")) + }, { _ in b.loadBool(true) }, { _ in } + ) { i in b.loopBreak() } @@ -3289,16 +3390,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i4 = (() => { - f(); - return g(); - })(); - ; - ) { - break; - } + for (let i4 = (() => { + f(); + return g(); + })(); + ; + ) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3308,7 +3409,10 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(variable: i, value: args[2], with: .Sub)}) { vars in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, + { i in b.reassign(variable: i, value: args[2], with: .Sub) } + ) { vars in } } @@ -3316,12 +3420,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2, a3) { - for (let i4 = a1; i4 >= a2; i4 -= a3) { + function f0(a1, a2, a3) { + for (let i4 = a1; i4 >= a2; i4 -= a3) { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3336,7 +3440,10 @@ class LifterTests: XCTestCase { let i = b.callFunction(b.createNamedVariable(forBuiltin: "i")) let j = b.callFunction(b.createNamedVariable(forBuiltin: "j")) - b.buildForLoop({ b.callFunction(print, withArgs: [f]) }, { b.callFunction(print, withArgs: [g]) }, { b.callFunction(print, withArgs: [h]) }) { + b.buildForLoop( + { b.callFunction(print, withArgs: [f]) }, { b.callFunction(print, withArgs: [g]) }, + { b.callFunction(print, withArgs: [h]) } + ) { b.callFunction(print, withArgs: [i]) } b.callFunction(print, withArgs: [j]) @@ -3345,17 +3452,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - const v8 = i(); - const v10 = j(); - for (print(v2); print(v4); print(v6)) { - print(v8); - } - print(v10); + const v2 = f(); + const v4 = g(); + const v6 = h(); + const v8 = i(); + const v10 = j(); + for (print(v2); print(v4); print(v6)) { + print(v8); + } + print(v10); - """ + """ XCTAssertEqual(actual, expected) } @@ -3366,7 +3473,13 @@ class LifterTests: XCTestCase { b.buildPlainFunction(with: .parameters(n: 0)) { _ in let s = b.loadInt(0) // Test that context-dependent operations such as LoadArguments are handled correctly inside loop headers - b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + b.compare( + i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) + }, { i in b.unary(.PostInc, i) } + ) { i in let arg = b.getComputedProperty(i, of: b.loadArguments()) b.reassign(variable: s, value: arg, with: .Add) } @@ -3377,15 +3490,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0() { - let v1 = 0; - for (let i3 = 0; i3 < arguments.length; i3++) { - v1 += arguments[i3]; + function f0() { + let v1 = 0; + for (let i3 = 0; i3 < arguments.length; i3++) { + v1 += arguments[i3]; + } + return v1; } - return v1; - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3405,13 +3518,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - for (let v1 = 0; v1 < 1337; v1++) { - v0 += v1; - } - print(v0); + let v0 = 0; + for (let v1 = 0; v1 < 1337; v1++) { + v0 += v1; + } + print(v0); - """ + """ XCTAssertEqual(actual, expected) } @@ -3420,12 +3533,14 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let a1 = b.createArray(with: [b.loadInt(10), b.loadInt(11), b.loadInt(12), b.loadInt(13), b.loadInt(14)]) + let a1 = b.createArray(with: [ + b.loadInt(10), b.loadInt(11), b.loadInt(12), b.loadInt(13), b.loadInt(14), + ]) let a2 = b.createArray(with: [b.loadInt(20), b.loadInt(21), b.loadInt(22), b.loadInt(23)]) let a3 = b.createArray(with: [b.loadInt(30), b.loadInt(31), b.loadInt(32)]) let a4 = b.createArray(with: [a1, a2, a3]) let print = b.createNamedVariable(forBuiltin: "print") - b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + b.buildForOfLoop(a4, selecting: [0, 2], hasRestElement: true) { args in b.callFunction(print, withArgs: [args[0]]) b.buildForOfLoop(args[1]) { v in b.callFunction(print, withArgs: [v]) @@ -3436,14 +3551,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let [v17,,...v18] of [[10,11,12,13,14],[20,21,22,23],[30,31,32]]) { - print(v17); - for (const v20 of v18) { - print(v20); + for (let [v17,,...v18] of [[10,11,12,13,14],[20,21,22,23],[30,31,32]]) { + print(v17); + for (const v20 of v18) { + print(v20); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3459,7 +3574,7 @@ class LifterTests: XCTestCase { let v3 = b.loadInt(1337) b.reassign(variable: v2, value: v3) b.blockStatement { - let v4 = b.createObject(with: ["a" : v1]) + let v4 = b.createObject(with: ["a": v1]) b.reassign(variable: v2, value: v4) } @@ -3470,17 +3585,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { a: 1337 }; - for (let v2 in v1) { - { - v2 = 1337; + const v1 = { a: 1337 }; + for (let v2 in v1) { { - v2 = { a: v1 }; + v2 = 1337; + { + v2 = { a: v1 }; + } } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3546,28 +3661,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - this.foo = a2; + class C0 { + constructor(a2) { + this.foo = a2; + } + baz() { + return this.bar; + } } - baz() { - return this.bar; + const v10 = { foo: 42, __proto__: proto1, bar: 42, baz: 42 }; + switch (42) { + default: + print("default case 1"); + break; + case 43: + print("case 43"); + break; + case 44: + print("case 44"); + break; } - } - const v10 = { foo: 42, __proto__: proto1, bar: 42, baz: 42 }; - switch (42) { - default: - print("default case 1"); - break; - case 43: - print("case 43"); - break; - case 44: - print("case 44"); - break; - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3606,31 +3721,31 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = this; - v0 = 42; - function F2() { - if (!new.target) { throw 'must be called with new'; } - let v3 = this; - v3 = 42; - } - const v5 = { - foo() { - let v4 = this; - v4 = 42; - }, - }; - class C6 { - bar() { - let v7 = this; - v7 = 42; - } - static get baz() { - let v8 = this; - v8 = 42; + let v0 = this; + v0 = 42; + function F2() { + if (!new.target) { throw 'must be called with new'; } + let v3 = this; + v3 = 42; + } + const v5 = { + foo() { + let v4 = this; + v4 = 42; + }, + }; + class C6 { + bar() { + let v7 = this; + v7 = 42; + } + static get baz() { + let v8 = this; + v8 = 42; + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3667,19 +3782,19 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - -(-42); - -(-43n); - -(-4.4); - (-42) ** -4.4; - ~-42; - -42 + -4.4; - let v9 = 42; - v9 = -42; - print(-42, -43n, -4.4); - (-43n).foo; - (-4.4).bar; - - """ + -(-42); + -(-43n); + -(-4.4); + (-42) ** -4.4; + ~-42; + -42 + -4.4; + let v9 = 42; + v9 = -42; + print(-42, -43n, -4.4); + (-43n).foo; + (-4.4).bar; + + """ XCTAssertEqual(actual, expected) } @@ -3698,18 +3813,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = null; - function f1() { - v0 = new.target; - } + let v0 = null; + function f1() { + v0 = new.target; + } - """ + """ XCTAssertEqual(actual, expected) } // This test is parameterized for normal and named variables with the // respective concrete cases below. - func _testDisposableVariableLifting(_ variableName : String, generateVariable: (ProgramBuilder, Variable) -> Void) { + func _testDisposableVariableLifting( + _ variableName: String, generateVariable: (ProgramBuilder, Variable) -> Void + ) { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -3717,12 +3834,12 @@ class LifterTests: XCTestCase { let v1 = b.loadInt(1) let v2 = b.loadInt(42) let numVariables = b.numberOfVisibleVariables - let dispose = b.createSymbolProperty("dispose"); + let dispose = b.createSymbolProperty("dispose") // Test that the intermediate variable for "Symbol" stays hidden. XCTAssertEqual(b.numberOfVisibleVariables, numVariables + 1) let disposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) - obj.addComputedMethod(dispose, with: .parameters(n:0)) { args in + obj.addComputedMethod(dispose, with: .parameters(n: 0)) { args in b.doReturn(v2) } } @@ -3734,37 +3851,43 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0() { - const v4 = Symbol.dispose; - const v6 = { - value: 1, - [v4]() { - return 42; - }, - }; - using %@ = v6; - } - f0(); + function f0() { + const v4 = Symbol.dispose; + const v6 = { + value: 1, + [v4]() { + return 42; + }, + }; + using %@ = v6; + } + f0(); - """ + """ XCTAssertEqual(actual, String(format: expected, variableName)) } func testLoadDisposableVariableLifting() { - _testDisposableVariableLifting("v7", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.loadDisposableVariable(v) - }) + _testDisposableVariableLifting( + "v7", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.loadDisposableVariable(v) + }) } func testCreateNamedDisposableVariableLifting() { - _testDisposableVariableLifting("dis", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.createNamedDisposableVariable("dis", v) - }) + _testDisposableVariableLifting( + "dis", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.createNamedDisposableVariable("dis", v) + }) } // This test is parameterized for normal and named variables with the // respective concrete cases below. - func _testAsyncDisposableVariableLifting(_ variableName : String, generateVariable: (ProgramBuilder, Variable) -> Void) { + func _testAsyncDisposableVariableLifting( + _ variableName: String, generateVariable: (ProgramBuilder, Variable) -> Void + ) { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -3774,7 +3897,7 @@ class LifterTests: XCTestCase { let asyncDispose = b.createSymbolProperty("asyncDispose") let asyncDisposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) - obj.addComputedMethod(asyncDispose, with: .parameters(n:0)) { args in + obj.addComputedMethod(asyncDispose, with: .parameters(n: 0)) { args in b.doReturn(v2) } } @@ -3790,45 +3913,50 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - async function f0() { - const v4 = Symbol.asyncDispose; - const v6 = { - value: 1, - [v4]() { - return 42; - }, - }; - await using %@ = v6; - } - async function f8() { - await f0(); - } - f8(); + async function f0() { + const v4 = Symbol.asyncDispose; + const v6 = { + value: 1, + [v4]() { + return 42; + }, + }; + await using %@ = v6; + } + async function f8() { + await f0(); + } + f8(); - """ + """ XCTAssertEqual(actual, String(format: expected, variableName)) } func testLoadAsyncDisposableVariableLifting() { - _testAsyncDisposableVariableLifting("v7", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.loadAsyncDisposableVariable(v) - }) + _testAsyncDisposableVariableLifting( + "v7", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.loadAsyncDisposableVariable(v) + }) } func testCreateNamedAsyncDisposableVariableLifting() { - _testAsyncDisposableVariableLifting("dis", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.createNamedAsyncDisposableVariable("dis", v) - }) + _testAsyncDisposableVariableLifting( + "dis", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.createNamedAsyncDisposableVariable("dis", v) + }) } func testImportAnalysisMisTypedJS() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let table = b.createWasmTable(elementType: .wasmFuncRef(), limits: Limits(min: 1), isTable64: true) + let table = b.createWasmTable( + elementType: .wasmFuncRef(), limits: Limits(min: 1), isTable64: true) XCTAssertTrue(b.type(of: table).Is(.object(ofGroup: "WasmTable"))) - let f = b.buildPlainFunction(with: .parameters(n: 0)) {_ in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in b.doReturn(b.loadInt(1)) } @@ -3840,7 +3968,8 @@ class LifterTests: XCTestCase { b.buildWasmModule { m in m.addWasmFunction(with: [] => []) { f, _, _ in - f.wasmCallIndirect(signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) + f.wasmCallIndirect( + signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) return [] } } @@ -3865,7 +3994,7 @@ class LifterTests: XCTestCase { // Append the mutated instruction now. b.append(instr) // Adopt the rest of the Program. - for i in mutationIndex+1.. v2] - v3, v4 <- WasmEndTypeGroup [v1, v2] - WasmBeginTypeGroup - v5 <- WasmDefineForwardOrSelfReference - v6 <- WasmDefineStructType(.wasmRef(Index) mutability=false, .wasmi32 mutability=true, .wasmRef(null Index) mutability=true) [v3, v5] - v7 <- WasmEndTypeGroup [v6] - - """ + WasmBeginTypeGroup + v0 <- WasmDefineForwardOrSelfReference + v1 <- WasmDefineArrayType .wasmRef(null Index) mutability=false v0 + v2 <- WasmDefineArrayType .wasmi32 mutability=true + WasmResolveForwardReference [v0 => v2] + v3, v4 <- WasmEndTypeGroup [v1, v2] + WasmBeginTypeGroup + v5 <- WasmDefineForwardOrSelfReference + v6 <- WasmDefineStructType(.wasmRef(Index) mutability=false, .wasmi32 mutability=true, .wasmRef(null Index) mutability=true) [v3, v5] + v7 <- WasmEndTypeGroup [v6] + + """ XCTAssertEqual(actual, expected) } @@ -3969,11 +4100,11 @@ class LifterTests: XCTestCase { // The side-effect must be emitted before the arrow function is defined. // The arrow function is assigned to a temporary because it's used as a callee. let expected = """ - sideEffect(); - const t1 = () => 42; - t1(); + sideEffect(); + const t1 = () => 42; + t1(); - """ + """ XCTAssertEqual(actual, expected) } @@ -3992,7 +4123,7 @@ class LifterTests: XCTestCase { b2.doReturn(b2.loadInt(0)) } let sub = b2.binary(arg0, b2.loadInt(1), with: .Sub) - let recCall = b2.callFunction(fRec, withArgs: [sub]) // Recursion! + let recCall = b2.callFunction(fRec, withArgs: [sub]) // Recursion! b2.doReturn(recCall) b2.emit(EndArrowFunction()) @@ -4003,15 +4134,15 @@ class LifterTests: XCTestCase { // Recursive arrow functions are not inlined, so they are assigned to a constant. let expected = """ - const v1 = (a2) => { - if (a2 == 0) { - return 0; - } - return v1(a2 - 1); - }; - v1(10); + const v1 = (a2) => { + if (a2 == 0) { + return 0; + } + return v1(a2 - 1); + }; + v1(10); - """ + """ XCTAssertEqual(actual, expected) } @@ -4029,9 +4160,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - f((a2) => a2); + f((a2) => a2); - """ + """ XCTAssertEqual(actual, expected) } @@ -4041,7 +4172,7 @@ class LifterTests: XCTestCase { let arrowOuter = b.buildArrowFunction(with: .parameters(n: 1)) { argsOuter in let arrowInner = b.buildArrowFunction(with: .parameters(n: 1)) { argsInner in - b.doReturn(b.binary(argsOuter[0], argsInner[0], with: .Add)) + b.doReturn(b.binary(argsOuter[0], argsInner[0], with: .Add)) } b.doReturn(arrowInner) } @@ -4051,10 +4182,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = (a1) => (a3) => a1 + a3; - t0(1); + const t0 = (a1) => (a3) => a1 + a3; + t0(1); - """ + """ XCTAssertEqual(actual, expected) } @@ -4071,10 +4202,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = async () => 42; - t0(); + const t0 = async () => 42; + t0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -4090,11 +4221,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = () => { - }; - f(v0, v0); + const v0 = () => { + }; + f(v0, v0); - """ + """ XCTAssertEqual(actual, expected) } @@ -4112,9 +4243,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - obj.x = () => 42; + obj.x = () => 42; - """ + """ XCTAssertEqual(actual, expected) } @@ -4132,10 +4263,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0.x = () => ({}); + const v0 = {}; + v0.x = () => ({}); - """ + """ XCTAssertEqual(actual, expected) } @@ -4146,7 +4277,8 @@ class LifterTests: XCTestCase { b.buildIf(b.loadBool(true)) { let o = b.buildObjectLiteral { _ in } let f = b.buildArrowFunction(with: .parameters(n: 0)) { _ in - let v = b.createNamedVariable("a", declarationMode: .const, initialValue: b.loadInt(1)) + let v = b.createNamedVariable( + "a", declarationMode: .const, initialValue: b.loadInt(1)) b.doReturn(b.binary(v, v, with: .Add)) } b.setProperty("x", of: o, to: f) @@ -4156,15 +4288,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - if (true) { - const v1 = {}; - v1.x = () => { - const a = 1; - return a + a; - }; - } + if (true) { + const v1 = {}; + v1.x = () => { + const a = 1; + return a + a; + }; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -4183,10 +4315,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = () => ({} + 1); - t0(); + const t0 = () => ({} + 1); + t0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -4200,9 +4332,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - print("Hello \\"World\\""); + print("Hello \\"World\\""); - """ + """ XCTAssertEqual(actual, expected) } @@ -4210,17 +4342,17 @@ class LifterTests: XCTestCase { func testEmptyWasmModule() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildWasmModule {_ in} + b.buildWasmModule { _ in } let program = b.finalize() let actual = fuzzer.lifter.lift(program) // An empty Wasm module should only contain the needed prefix but no empty sections. let expected = """ - const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ - 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, - ]))); + const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ]))); - """ + """ XCTAssertEqual(actual, expected) } diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 535e6401f..fed055235 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class LiveTests: XCTestCase { @@ -26,12 +27,13 @@ class LiveTests: XCTestCase { /// Meta-test ensuring that the test framework can successfully terminate an endless loop. func testEndlessLoopTermination() throws { - let runner = try GetJavaScriptExecutorOrSkipTest() + let runner = try GetJavaScriptExecutorOrSkipTest() - let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { b in - b.loadInt(123) // prefix + let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { + b in + b.loadInt(123) // prefix - let module = b.buildWasmModule() { module in + let module = b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in function.wasmBuildLoop(with: [] => [], args: []) { label, args in function.wasmBranch(to: label) @@ -58,7 +60,8 @@ class LiveTests: XCTestCase { } func testWasmCodeGenerationAndCompilation() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) let results = try Self.runLiveTest(withRunner: runner) { b in // Fuzzilli can't handle situations where there aren't any variables available. @@ -80,13 +83,16 @@ class LiveTests: XCTestCase { b.createWasmJSTag() b.createWasmTag(parameterTypes: [.wasmi32, .wasmf64]) - b.buildWasmModule() { module in - module.addMemory(minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) + b.buildWasmModule { module in + module.addMemory( + minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) let signature = b.randomWasmSignature() module.addWasmFunction(with: signature) { function, label, args in b.buildPrefix() b.build(n: 40) - return signature.outputTypes.map {b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)!} + return signature.outputTypes.map { + b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)! + } } } } @@ -96,7 +102,8 @@ class LiveTests: XCTestCase { } func testWasmCodeGenerationAndCompilationAndExecution() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) let results = try Self.runLiveTest(withRunner: runner) { b in // Fuzzilli can't handle situations where there aren't any variables available. @@ -119,12 +126,15 @@ class LiveTests: XCTestCase { b.createWasmTag(parameterTypes: [.wasmi32, .wasmf64]) let wasmSignature = b.randomWasmSignature() - let m = b.buildWasmModule() { module in - module.addMemory(minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) + let m = b.buildWasmModule { module in + module.addMemory( + minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) module.addWasmFunction(with: wasmSignature) { function, label, args in b.buildPrefix() b.build(n: 40) - return wasmSignature.outputTypes.map {b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)!} + return wasmSignature.outputTypes.map { + b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)! + } } } @@ -136,16 +146,16 @@ class LiveTests: XCTestCase { // TODO(pawkra): support shared refs. let args = wasmSignature.parameterTypes.map { switch $0 { - case .wasmi64: - return b.loadBigInt(123) - case ILType.wasmFuncRef(): - return jsFunction - case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): - return b.loadNull() - case ILType.wasmExternRef(), ILType.wasmAnyRef(): - return b.createObject(with: [:]) - default: - return b.loadInt(321) + case .wasmi64: + return b.loadBigInt(123) + case ILType.wasmFuncRef(): + return jsFunction + case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): + return b.loadNull() + case ILType.wasmExternRef(), ILType.wasmAnyRef(): + return b.createObject(with: [:]) + default: + return b.loadInt(321) } } b.callMethod(m.getExportedMethod(at: 0), on: m.loadExports(), withArgs: args) @@ -166,7 +176,10 @@ class LiveTests: XCTestCase { // The closure can use the ProgramBuilder to emit a program of a specific // shape that is then executed with the given runner. We then check that // we stay below the maximum failure rate over the given number of iterations. - static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { + static func runLiveTest( + iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, + body: (ProgramBuilder) -> Void + ) throws -> (failureRate: Double, failureMessages: [String: Int]) { let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -178,11 +191,13 @@ class LiveTests: XCTestCase { var failureDirectory: URL? = nil if ProcessInfo.processInfo.environment["FUZZILLI_TEST_DEBUG"] != nil { - failureDirectory = FileManager().temporaryDirectory.appendingPathComponent("fuzzilli_livetest_failures") + failureDirectory = FileManager().temporaryDirectory.appendingPathComponent( + "fuzzilli_livetest_failures") print("Saving LiveTest failures to \(String(describing: failureDirectory!)).") do { try? FileManager.default.removeItem(at: failureDirectory!) - try FileManager.default.createDirectory(at: failureDirectory!, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + at: failureDirectory!, withIntermediateDirectories: true) } catch {} } @@ -202,7 +217,8 @@ class LiveTests: XCTestCase { } DispatchQueue.concurrentPerform(iterations: n) { i in - let result = executeAndParseResults(program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) + let result = executeAndParseResults( + program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) results[i] = result } @@ -210,7 +226,8 @@ class LiveTests: XCTestCase { switch result! { case .failed(let message): if let path = failureDirectory { - programs[i].program.storeToDisk(atPath: path.appendingPathComponent("failure_\(i).fzil").path) + programs[i].program.storeToDisk( + atPath: path.appendingPathComponent("failure_\(i).fzil").path) } failures += 1 failureMessages[message] = (failureMessages[message] ?? 0) + 1 @@ -224,24 +241,33 @@ class LiveTests: XCTestCase { return (failureRate, failureMessages) } - func checkFailureRate(testResults: (failureRate: Double, failureMessages: [String: Int]), maxFailureRate: Double) { + func checkFailureRate( + testResults: (failureRate: Double, failureMessages: [String: Int]), maxFailureRate: Double + ) { if testResults.failureRate >= maxFailureRate { - var message = "Failure rate is too high. Should be below \(String(format: "%.2f", maxFailureRate * 100))% but we observed \(String(format: "%.2f", testResults.failureRate * 100))%\n" + var message = + "Failure rate is too high. Should be below \(String(format: "%.2f", maxFailureRate * 100))% but we observed \(String(format: "%.2f", testResults.failureRate * 100))%\n" message += "Observed failures:\n" - for (signature, count) in testResults.failureMessages.sorted(by: { $0.value > $1.value }) { + for (signature, count) in testResults.failureMessages.sorted(by: { $0.value > $1.value } + ) { message += " \(count)x \(signature)\n" } if ProcessInfo.processInfo.environment["FUZZILLI_TEST_DEBUG"] == nil { - message += "If you want to dump failing programs to disk you can set FUZZILLI_TEST_DEBUG=1 in your environment." + message += + "If you want to dump failing programs to disk you can set FUZZILLI_TEST_DEBUG=1 in your environment." } XCTFail(message) } } - static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, timeoutInSeconds: Int) -> ExecutionResult { + static func executeAndParseResults( + program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, + timeoutInSeconds: Int + ) -> ExecutionResult { do { - let result = try runner.executeScript(program.jsProgram, + let result = try runner.executeScript( + program.jsProgram, withTimeout: Double(timeoutInSeconds) * Seconds) if result.isFailure { var signature: String? = nil diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 2878c9431..7ecaf6dbe 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class MinimizerTests: XCTestCase { @@ -609,11 +610,14 @@ class MinimizerTests: XCTestCase { // Build input program to be minimized. b.loadString("unused") let f = b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(args[1]) - }, elseBody: { - b.doReturn(args[2]) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(args[1]) + }, + elseBody: { + b.doReturn(args[2]) + }) } var a1 = b.loadBool(true) var a2 = b.loadInt(1337) @@ -636,11 +640,14 @@ class MinimizerTests: XCTestCase { a2 = b.loadInt(1337) let u = b.loadUndefined() r = b.loadUndefined() - b.buildIfElse(a1, ifBody: { - b.reassign(variable: r, value: a2) - }, elseBody: { - b.reassign(variable: r, value: u) - }) + b.buildIfElse( + a1, + ifBody: { + b.reassign(variable: r, value: a2) + }, + elseBody: { + b.reassign(variable: r, value: u) + }) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: r) @@ -685,9 +692,11 @@ class MinimizerTests: XCTestCase { var a3 = b.loadInt(2) b.loadString("unused") let f = b.buildPlainFunction(with: .parameters(n: 0)) { args in - b.buildIf(a1, ifBody: { - b.doReturn(a2) - }) + b.buildIf( + a1, + ifBody: { + b.doReturn(a2) + }) b.doReturn(a3) } @@ -710,9 +719,11 @@ class MinimizerTests: XCTestCase { a2 = b.loadInt(1) a3 = b.loadInt(2) r = b.loadUndefined() - b.buildIf(a1, ifBody: { - b.reassign(variable: r, value: a2) - }) + b.buildIf( + a1, + ifBody: { + b.reassign(variable: r, value: a2) + }) b.reassign(variable: r, value: a3) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: a3) @@ -838,23 +849,26 @@ class MinimizerTests: XCTestCase { b.reassign(variable: n3, value: n1) var n4 = b.loadInt(45) b.reassign(variable: n4, value: n3) - b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 + b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 var c = b.loadBool(true) - b.buildIfElse(c, ifBody: { - let n5 = b.loadInt(46) - b.reassign(variable: n1, value: n5) - b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 - b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 - b.reassign(variable: n1, value: n2) - b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 - }, elseBody: { - let n6 = b.loadInt(47) - b.reassign(variable: n1, value: n6) - b.setProperty( "n3", of: o, to: n3) // This will still store n3, i.e. 42 - }) - b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 + b.buildIfElse( + c, + ifBody: { + let n5 = b.loadInt(46) + b.reassign(variable: n1, value: n5) + b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 + b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 + b.reassign(variable: n1, value: n2) + b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 + }, + elseBody: { + let n6 = b.loadInt(47) + b.reassign(variable: n1, value: n6) + b.setProperty("n3", of: o, to: n3) // This will still store n3, i.e. 42 + }) + b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 b.reassign(variable: n1, value: n2) - b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 + b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 evaluator.operationIsImportant(Reassign.self) @@ -874,18 +888,21 @@ class MinimizerTests: XCTestCase { b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n1) c = b.loadBool(true) - b.buildIfElse(c, ifBody: { - let n5 = b.loadInt(46) - b.reassign(variable: n1, value: n5) - b.setProperty("n1", of: o, to: n5) - b.setProperty("n1", of: o, to: n5) - b.reassign(variable: n1, value: n2) - b.setProperty("n1", of: o, to: n2) - }, elseBody: { - let n6 = b.loadInt(47) - b.reassign(variable: n1, value: n6) - b.setProperty("n3", of: o, to: n3) - }) + b.buildIfElse( + c, + ifBody: { + let n5 = b.loadInt(46) + b.reassign(variable: n1, value: n5) + b.setProperty("n1", of: o, to: n5) + b.setProperty("n1", of: o, to: n5) + b.reassign(variable: n1, value: n2) + b.setProperty("n1", of: o, to: n2) + }, + elseBody: { + let n6 = b.loadInt(47) + b.reassign(variable: n1, value: n6) + b.setProperty("n3", of: o, to: n3) + }) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n1", of: o, to: n1) b.reassign(variable: n1, value: n2) @@ -999,7 +1016,7 @@ class MinimizerTests: XCTestCase { let loopVar = b.loadInt(0) b.buildWhileLoop({ b.compare(loopVar, with: numIterations, using: .lessThan) }) { b.unary(.PostInc, loopVar) - evaluator.nextInstructionIsImportant(in: b) // Otherwise, the minimizer will attempt to simplify the while-loop into a repeat-loop + evaluator.nextInstructionIsImportant(in: b) // Otherwise, the minimizer will attempt to simplify the while-loop into a repeat-loop b.buildWhileLoop({ b.loadBool(true) }) { evaluator.nextInstructionIsImportant(in: b) b.loopBreak() @@ -1037,9 +1054,22 @@ class MinimizerTests: XCTestCase { var f = b.createNamedVariable(forBuiltin: "f") var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") - b.buildForLoop(i: { evaluator.nextInstructionIsImportant(in: b); return b.callFunction(d) }, - { i in evaluator.nextInstructionIsImportant(in: b); b.callFunction(e); return b.compare(i, with: b.loadInt(100), using: .lessThan) }, - { i in evaluator.nextInstructionIsImportant(in: b); b.callFunction(f); b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { + evaluator.nextInstructionIsImportant(in: b) + return b.callFunction(d) + }, + { i in + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(e) + return b.compare(i, with: b.loadInt(100), using: .lessThan) + }, + { i in + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f) + b.unary(.PostInc, i) + } + ) { i in evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [i]) } @@ -1082,9 +1112,23 @@ class MinimizerTests: XCTestCase { var h = b.createNamedVariable(forBuiltin: "h") var limit = b.loadInt(100) // In this case, the for-loop is actually important (we emulate that by marking the EndForLoopAfterthought instruction as important - b.buildForLoop(i: { evaluator.nextInstructionIsImportant(in: b); return b.callFunction(d) }, - { i in b.callFunction(e); evaluator.nextInstructionIsImportant(in: b); return b.compare(i, with: limit, using: .lessThan) }, - { i in b.callFunction(f); evaluator.nextInstructionIsImportant(in: b); b.unary(.PostInc, i); evaluator.nextInstructionIsImportant(in: b) }) { i in + b.buildForLoop( + i: { + evaluator.nextInstructionIsImportant(in: b) + return b.callFunction(d) + }, + { i in + b.callFunction(e) + evaluator.nextInstructionIsImportant(in: b) + return b.compare(i, with: limit, using: .lessThan) + }, + { i in + b.callFunction(f) + evaluator.nextInstructionIsImportant(in: b) + b.unary(.PostInc, i) + evaluator.nextInstructionIsImportant(in: b) + } + ) { i in evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [i]) } @@ -1098,9 +1142,11 @@ class MinimizerTests: XCTestCase { g = b.createNamedVariable(forBuiltin: "g") h = b.createNamedVariable(forBuiltin: "h") limit = b.loadInt(100) - b.buildForLoop(i: { return b.callFunction(d) }, - { i in b.compare(i, with: limit, using: .lessThan) }, - { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { return b.callFunction(d) }, + { i in b.compare(i, with: limit, using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(g, withArgs: [i]) } b.callFunction(h) @@ -1122,7 +1168,12 @@ class MinimizerTests: XCTestCase { var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") var loopVar = b.loadInt(10) - b.buildWhileLoop({ evaluator.nextInstructionIsImportant(in: b); b.callFunction(f); evaluator.nextInstructionIsImportant(in: b); return b.unary(.PostDec, loopVar) }) { + b.buildWhileLoop({ + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f) + evaluator.nextInstructionIsImportant(in: b) + return b.unary(.PostDec, loopVar) + }) { evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [loopVar]) @@ -1165,14 +1216,20 @@ class MinimizerTests: XCTestCase { var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") var loopVar = b.loadInt(10) - b.buildDoWhileLoop(do: { - evaluator.nextInstructionIsImportant(in: b) - b.callFunction(f, withArgs: [loopVar]) + b.buildDoWhileLoop( + do: { + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f, withArgs: [loopVar]) - evaluator.nextInstructionIsImportant(in: b) - // The Continue operation is necessary here so that the loop isn't simply deleted. - b.loopContinue() - }, while: { evaluator.nextInstructionIsImportant(in: b); b.callFunction(g); return b.unary(.PostDec, loopVar) }) + evaluator.nextInstructionIsImportant(in: b) + // The Continue operation is necessary here so that the loop isn't simply deleted. + b.loopContinue() + }, + while: { + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(g) + return b.unary(.PostDec, loopVar) + }) evaluator.nextInstructionIsImportant(in: b) b.callFunction(h) @@ -1342,10 +1399,11 @@ class MinimizerTests: XCTestCase { evaluator.nextInstructionIsImportant(in: b) var a = b.createArray(with: [i, i, i]) var f = b.loadFloat(13.37) - b.buildTryCatchFinally(tryBody: { - evaluator.nextInstructionIsImportant(in: b) - b.callMethod("fill", on: a, withArgs: [f]) - }, catchBody: { _ in }) + b.buildTryCatchFinally( + tryBody: { + evaluator.nextInstructionIsImportant(in: b) + b.callMethod("fill", on: a, withArgs: [f]) + }, catchBody: { _ in }) let originalProgram = b.finalize() @@ -1529,7 +1587,10 @@ class MinimizerTests: XCTestCase { b.callMethod("m", on: o, guard: true) // Make sure that none of the operations are removed. - evaluator.operationsAreImportant([GetProperty.self, GetElement.self, GetComputedProperty.self, CallFunction.self, CallMethod.self]) + evaluator.operationsAreImportant([ + GetProperty.self, GetElement.self, GetComputedProperty.self, CallFunction.self, + CallMethod.self, + ]) let originalProgram = b.finalize() @@ -1538,8 +1599,12 @@ class MinimizerTests: XCTestCase { let minimizedProgram = minimize(originalProgram, with: fuzzer) XCTAssertEqual(originalProgram.size, minimizedProgram.size) - let numGuardableOperationsBefore = originalProgram.code.filter({ $0.op is GuardableOperation }).count - let numGuardableOperationsAfter = minimizedProgram.code.filter({ $0.op is GuardableOperation }).count + let numGuardableOperationsBefore = originalProgram.code.filter({ + $0.op is GuardableOperation + }).count + let numGuardableOperationsAfter = minimizedProgram.code.filter({ + $0.op is GuardableOperation + }).count XCTAssertEqual(numGuardableOperationsBefore, numGuardableOperationsAfter) let operationTypesBefore = originalProgram.code.map({ $0.op.name }) @@ -1552,7 +1617,10 @@ class MinimizerTests: XCTestCase { XCTAssertEqual(numGuardedOperationsAfter, 0) } - func runWasmMinimization(program: (MinimizerTests.EvaluatorForMinimizationTests, ProgramBuilder) -> ProgramBuilder.WasmModule, minified: (ProgramBuilder) -> ProgramBuilder.WasmModule) throws { + func runWasmMinimization( + program: (MinimizerTests.EvaluatorForMinimizationTests, ProgramBuilder) -> + ProgramBuilder.WasmModule, minified: (ProgramBuilder) -> ProgramBuilder.WasmModule + ) throws { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) let b = fuzzer.makeBuilder() @@ -1573,9 +1641,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } // Test removing unneeded WasmBeginCatchAll blocks. @@ -1616,18 +1685,24 @@ class MinimizerTests: XCTestCase { let irrelevantTag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in evaluator.nextInstructionIsImportant(in: b) function.WasmBuildThrow(tag: tag, inputs: []) // Mark teh first catch as important. evaluator.nextInstructionIsImportant(in: b) - }, catchClauses: [ - (tag: tag, body: { _, _, _ in - let val = function.consti64(42) - evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - }), - (tag: irrelevantTag, body: { _, _, _ in })]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, _ in + let val = function.consti64(42) + evaluator.nextInstructionIsImportant(in: b) + function.wasmReturn(val) + } + ), + (tag: irrelevantTag, body: { _, _, _ in }), + ]) return [function.consti64(-1)] } } @@ -1639,9 +1714,15 @@ class MinimizerTests: XCTestCase { function.wasmBuildLegacyTryVoid( body: { label in function.WasmBuildThrow(tag: tag, inputs: []) - }, catchClauses: [(tag: tag, body: { _, _, _ in - function.wasmReturn(function.consti64(42)) - })]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, _ in + function.wasmReturn(function.consti64(42)) + } + ) + ]) return [function.consti64(-1)] } } @@ -1654,11 +1735,13 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in let tag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in let val = function.consti64(42) - evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) + evaluator.nextInstructionIsImportant(in: b) + function.wasmReturn(val) + }, + catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) return [function.consti64(-1)] } } @@ -1666,8 +1749,8 @@ class MinimizerTests: XCTestCase { } minified: { b in return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmReturn(function.consti64(42)) - return [function.consti64(-1)] + function.wasmReturn(function.consti64(42)) + return [function.consti64(-1)] } } } @@ -1703,7 +1786,7 @@ class MinimizerTests: XCTestCase { function.wasmBuildIfElse(args[0], signature: [] => []) { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(43) - } elseBody: { _, _ in + } elseBody: { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(42) } @@ -1725,9 +1808,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationVoidRemoveElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { label, ifArgs in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { label, ifArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) evaluator.nextInstructionIsImportant(in: b) @@ -1741,8 +1827,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { label, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { label, ifArgs in let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) function.wasmReturn(sum) } @@ -1755,9 +1844,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationVoidRemoveIfKeepElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in evaluator.operationIsImportant(WasmBeginIf.self) - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { _, _ in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { _, _ in function.wasmUnreachable() } elseBody: { label, elseArgs in evaluator.nextInstructionIsImportant(in: b) @@ -1771,8 +1863,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: true) { label, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: true + ) { label, ifArgs in let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) function.wasmReturn(sum) } @@ -1785,8 +1880,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResult() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) let a = function.consti32(42) evaluator.nextInstructionIsImportant(in: b) @@ -1800,7 +1898,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let b = function.consti32(10) let a = function.consti32(42) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1812,8 +1911,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultKeepElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1827,7 +1929,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let b = function.consti32(10) let a = function.consti32(42) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1840,8 +1943,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultButLabelUsedInIf() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) function.wasmBranch(to: label, args: args) return [args[0]] @@ -1854,8 +1960,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in function.wasmBranch(to: label, args: args) return [args[0]] } elseBody: { label, args in @@ -1871,8 +1980,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultButLabelUsedInElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1885,8 +1997,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in function.wasmBranch(to: label, args: args) @@ -1901,8 +2016,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultPassingThroughInputInIf() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], + args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) return [args[0], function.consti32(123)] } elseBody: { label, args in @@ -1915,7 +2034,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let a = function.consti32(10) let b = function.consti32(123) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1927,8 +2047,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultPassingThroughInputInElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], + args: [function.consti32(10)] + ) { label, args in return [args[0], args[0]] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1941,7 +2065,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let a = function.consti32(10) let b = function.consti32(123) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1953,8 +2078,12 @@ class MinimizerTests: XCTestCase { func testWasmBlockMinimization() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(blockArgs[0], blockArgs[1], binOpKind: .Add) return [sum, blockArgs[1]] @@ -1965,9 +2094,10 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let const10 = function.consti32(10) + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let const10 = function.consti32(10) let sum = function.wasmi32BinOp(args[0], const10, binOpKind: .Add) return [function.wasmi32BinOp(sum, const10, binOpKind: .Mul)] } @@ -1979,8 +2109,12 @@ class MinimizerTests: XCTestCase { func testWasmBlockMinimizationLabelUsed() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) function.wasmBranch(to: label, args: blockArgs) return blockArgs @@ -1991,9 +2125,13 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in function.wasmBranch(to: label, args: blockArgs) return blockArgs } @@ -2006,8 +2144,12 @@ class MinimizerTests: XCTestCase { func testWasmLoopMinimization() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildLoop(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildLoop( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(blockArgs[0], blockArgs[1], binOpKind: .Add) return [sum, blockArgs[1]] @@ -2018,9 +2160,10 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let const10 = function.consti32(10) + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let const10 = function.consti32(10) let sum = function.wasmi32BinOp(args[0], const10, binOpKind: .Add) return [function.wasmi32BinOp(sum, const10, binOpKind: .Mul)] } @@ -2083,9 +2226,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2115,7 +2259,8 @@ class MinimizerTests: XCTestCase { let constOne = function.consti32(1) let constZero = function.consti32(0) evaluator.nextInstructionIsImportant(in: b) - let array = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: constOne) + let array = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: constOne) // Not important array, this should make the second type unused and then being // removed from the type group. let _ = function.wasmArrayNewDefault(arrayType: typeGroup[1], size: constOne) @@ -2138,7 +2283,8 @@ class MinimizerTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let constOne = function.consti32(1) let constZero = function.consti32(0) - let array = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: constOne) + let array = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: constOne) let element = function.wasmArrayGet(array: array, index: constZero) return [element] } @@ -2148,9 +2294,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2165,8 +2312,11 @@ class MinimizerTests: XCTestCase { // This signature is only used by the structType which is exposed from this type // group and then used in the struct.new_default inside the wasm function. Still, // due to this indirect usage it must still be kept alive. - let signature = b.wasmDefineSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) - let structType = b.wasmDefineStructType(fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [signature]) + let signature = b.wasmDefineSignatureType( + signature: [.wasmi32] => [.wasmi32], indexTypes: []) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], + indexTypes: [signature]) return [signature, structType] } @@ -2182,8 +2332,11 @@ class MinimizerTests: XCTestCase { // Build expected output program. do { let typeGroup = b.wasmDefineTypeGroup { - let signature = b.wasmDefineSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) - let structType = b.wasmDefineStructType(fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [signature]) + let signature = b.wasmDefineSignatureType( + signature: [.wasmi32] => [.wasmi32], indexTypes: []) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], + indexTypes: [signature]) return [signature, structType] } @@ -2197,12 +2350,12 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } - func testWasmTypeGroupNestedTypesAndTypeGroupDependencies() throws { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -2223,9 +2376,13 @@ class MinimizerTests: XCTestCase { let typeGroupB = b.wasmDefineTypeGroup { return [ // Only used by an unimportant instruction. - b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: false), mutability: false, indexType: typeGroupA[2]), + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: false), mutability: false, + indexType: typeGroupA[2]), // Needed for an important instruction, shall not be removed. - b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: typeGroupA[1]), + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: typeGroupA[1]), ] } @@ -2247,7 +2404,11 @@ class MinimizerTests: XCTestCase { return [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] } let typeGroupB = b.wasmDefineTypeGroup { - return [b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: typeGroupA[0])] + return [ + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: typeGroupA[0]) + ] } b.buildWasmModule { wasmModule in @@ -2262,9 +2423,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2353,10 +2515,14 @@ class MinimizerTests: XCTestCase { func hasAspects(_ execution: Execution, _ aspects: ProgramAspects) -> Bool { // Check if any important instructions were removed, and if yes return false. - var numImportantOperationsBefore = 0, numImportantOperationsAfter = 0 - var numReturnsBefore = 0, numReturnsAfter = 0 - var numFunctionsBefore = 0, numFunctionsAfter = 0 - var numImportantInstructionsBefore = importantInstructions.count, numImportantInstructionsAfter = 0 + var numImportantOperationsBefore = 0 + var numImportantOperationsAfter = 0 + var numReturnsBefore = 0 + var numReturnsAfter = 0 + var numFunctionsBefore = 0 + var numFunctionsAfter = 0 + var numImportantInstructionsBefore = importantInstructions.count + var numImportantInstructionsAfter = 0 for instr in referenceProgram.code { if instr.op is BeginAnyFunction { @@ -2396,7 +2562,9 @@ class MinimizerTests: XCTestCase { } // When keepReturnsInFunctions is set, returns may only be removed if at least one function is also removed (e.g. by inlining) - if keepReturnsInFunctions && numReturnsBefore > numReturnsAfter && numFunctionsBefore == numFunctionsAfter { + if keepReturnsInFunctions && numReturnsBefore > numReturnsAfter + && numFunctionsBefore == numFunctionsAfter + { return false } @@ -2425,7 +2593,9 @@ class MinimizerTests: XCTestCase { func importState(_ state: Data) {} - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { return nil } @@ -2433,10 +2603,17 @@ class MinimizerTests: XCTestCase { } // Helper function to perform the minimization. - func minimize(_ program: Program, with fuzzer: Fuzzer, limit: Double = 0.0, performPostprocessing: Bool = true) -> Program { - guard let evaluator = fuzzer.evaluator as? EvaluatorForMinimizationTests else { fatalError("Invalid Evaluator used for minimization tests: \(fuzzer.evaluator)") } + func minimize( + _ program: Program, with fuzzer: Fuzzer, limit: Double = 0.0, + performPostprocessing: Bool = true + ) -> Program { + guard let evaluator = fuzzer.evaluator as? EvaluatorForMinimizationTests else { + fatalError("Invalid Evaluator used for minimization tests: \(fuzzer.evaluator)") + } evaluator.setOriginalProgram(program) let dummyAspects = ProgramAspects(outcome: .succeeded) - return fuzzer.minimizer.minimize(program, withAspects: dummyAspects, limit: limit, performPostprocessing: performPostprocessing) + return fuzzer.minimizer.minimize( + program, withAspects: dummyAspects, limit: limit, + performPostprocessing: performPostprocessing) } } diff --git a/Tests/FuzzilliTests/MutatorTests.swift b/Tests/FuzzilliTests/MutatorTests.swift index 394b0458f..08a6b2377 100644 --- a/Tests/FuzzilliTests/MutatorTests.swift +++ b/Tests/FuzzilliTests/MutatorTests.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest import Testing +import XCTest + @testable import Fuzzilli class MutatorTests: XCTestCase { @@ -109,7 +110,7 @@ class MutatorTests: XCTestCase { return "originalValue" } } - let mockNamedString = ILType.namedString(ofName: "NamedString"); + let mockNamedString = ILType.namedString(ofName: "NamedString") let env = JavaScriptEnvironment() env.addNamedStringGenerator(forType: mockNamedString, with: generateString) @@ -140,7 +141,7 @@ class MutatorTests: XCTestCase { let mutator = OperationMutator() for _ in 1...10 { let newBuilder = fuzzer.makeBuilder() - newBuilder.adopting() { + newBuilder.adopting { mutator.mutate(originalLoadInstruction[0], newBuilder) } @@ -153,7 +154,7 @@ class MutatorTests: XCTestCase { XCTAssertEqual(newLoadInstruction.count, 1) let newLoad = newLoadInstruction[0].op as! LoadString if newLoad.value == "newValue" { - return; + return } } XCTFail("Mutator ran 10 times without rerunning custom string generator") diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 7dc3dfd2a..0e98fb835 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ProgramBuilderTests: XCTestCase { @@ -39,7 +40,7 @@ class ProgramBuilderTests: XCTestCase { // On average, we should generate between n and 2x n instructions. let averageSize = sumOfProgramSizes / numPrograms - XCTAssertLessThanOrEqual(averageSize, 2*N) + XCTAssertLessThanOrEqual(averageSize, 2 * N) } func testTemplateBuilding() { @@ -129,9 +130,10 @@ class ProgramBuilderTests: XCTestCase { let simpleGenerator = CodeGenerator("SimpleGenerator", produces: [.integer]) { b in b.loadInt(Int64.random(in: 0..<100)) } - fuzzer.setCodeGenerators(WeightedList([ - (simpleGenerator, 1), - ])) + fuzzer.setCodeGenerators( + WeightedList([ + (simpleGenerator, 1) + ])) for _ in 0..<10 { b.buildPrefix() @@ -157,10 +159,11 @@ class ProgramBuilderTests: XCTestCase { b.build(n: 5) } } - fuzzer.setCodeGenerators(WeightedList([ - (simpleGenerator, 3), - (recursiveGenerator, 1), - ])) + fuzzer.setCodeGenerators( + WeightedList([ + (simpleGenerator, 3), + (recursiveGenerator, 1), + ])) for _ in 0..<10 { b.buildPrefix() @@ -312,22 +315,24 @@ class ProgramBuilderTests: XCTestCase { b.probabilityOfVariableSelectionTryingToFindAnExactMatch = 1.0 - do { // Search with exact match. + do { // Search with exact match. let (foundVar, matches) = b.randomVariable(forUseAsGuarded: b.type(of: obj)) XCTAssertEqual(obj, foundVar) XCTAssert(matches) } - do { // Search for supertype. - let (foundVar, matches) = b.randomVariable(forUseAsGuarded: .object(withProperties: ["x"])) + do { // Search for supertype. + let (foundVar, matches) = b.randomVariable( + forUseAsGuarded: .object(withProperties: ["x"])) XCTAssertEqual(obj, foundVar) XCTAssert(matches) } - do { // Search for subtype. - let (foundVar, matches) = b.randomVariable(forUseAsGuarded: .object(withProperties: ["x", "y", "z"])) + do { // Search for subtype. + let (foundVar, matches) = b.randomVariable( + forUseAsGuarded: .object(withProperties: ["x", "y", "z"])) XCTAssertEqual(obj, foundVar) XCTAssertFalse(matches) } - do { // Search for unrelated type. We ignore the variable, since it's completely random. + do { // Search for unrelated type. We ignore the variable, since it's completely random. let (_, matches) = b.randomVariable(forUseAsGuarded: .string) XCTAssertFalse(matches) } @@ -506,7 +511,8 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(42) b.loadInt(43) b.loadInt(44) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) // The same is true if we have variables of other types, but not enough to // ensure that a function using these types as parameter types can be called @@ -514,7 +520,8 @@ class ProgramBuilderTests: XCTestCase { let s = b.loadString("foo") let a = b.createIntArray(with: [1, 2, 3]) let o = b.createObject(with: [:]) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) // But as soon as we have a sufficient number of other types as well, // we expect those to be used as well. @@ -528,7 +535,11 @@ class ProgramBuilderTests: XCTestCase { let types = [b.type(of: i), b.type(of: s), b.type(of: a), b.type(of: o)] var usesOfParameterType = [ILType: Int]() for _ in 0..<100 { - guard case .plain(let paramType) = b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0] else { return XCTFail("Unexpected parameter" )} + guard + case .plain(let paramType) = b.randomParameters( + n: 1, withRestParameterProbability: 0 + ).parameterTypes[0] + else { return XCTFail("Unexpected parameter") } XCTAssert(types.contains(paramType)) usesOfParameterType[paramType] = (usesOfParameterType[paramType] ?? 0) + 1 } @@ -536,8 +547,12 @@ class ProgramBuilderTests: XCTestCase { // However, if we set the probability of using .jsAnything as parameter to 100%, we expect to only see .jsAnything parameters. b.probabilityOfUsingAnythingAsParameterTypeIfAvoidable = 1.0 - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything + ) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything + ) } func testParameterGeneration3() { @@ -560,7 +575,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssertEqual(b.type(of: p1), .object(withProperties: ["x", "y"])) XCTAssertEqual(b.type(of: p1), b.type(of: p2)) - let f1 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f1 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let p = args[0] XCTAssertEqual(b.type(of: p), b.type(of: p1)) XCTAssertEqual(b.type(of: p).properties, ["x", "y"]) @@ -580,7 +597,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssert(b.type(of: a1).properties.contains("length")) XCTAssert(b.type(of: a1).methods.contains("slice")) - let f2 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f2 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let a = args[0] XCTAssertEqual(b.type(of: a), b.type(of: a1)) } @@ -599,7 +618,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssertEqual(b.type(of: n1), b.type(of: n2)) XCTAssertEqual(b.type(of: n2), b.type(of: n3)) - let f3 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f3 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let a = args[0] XCTAssertEqual(b.type(of: a), b.type(of: n1)) } @@ -618,11 +639,14 @@ class ProgramBuilderTests: XCTestCase { let params = b.randomParameters(n: 2, withRestParameterProbability: 1.0) XCTAssertEqual(params.count, 2) XCTAssert(params.parameters.hasRestParameter) - guard case .plain(_) = params.parameterTypes[0] else { return XCTFail("Expected a plain parameter") } - guard case .rest(_) = params.parameterTypes[1] else { return XCTFail("Expected a rest parameter") } + guard case .plain(_) = params.parameterTypes[0] else { + return XCTFail("Expected a plain parameter") + } + guard case .rest(_) = params.parameterTypes[1] else { + return XCTFail("Expected a rest parameter") + } } - func testObjectLiteralBuilding() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -820,14 +844,17 @@ class ProgramBuilderTests: XCTestCase { let i1 = b.loadInt(0x41) var i2 = b.loadInt(0x42) let cond = b.compare(i1, with: i2, using: .lessThan) - b.buildIfElse(cond, ifBody: { - let String = b.createNamedVariable(forBuiltin: "String") - splicePoint = b.indexOfNextInstruction() - b.callMethod("fromCharCode", on: String, withArgs: [i1]) - b.callMethod("fromCharCode", on: String, withArgs: [i2]) - }, elseBody: { - b.binary(i1, i2, with: .Add) - }) + b.buildIfElse( + cond, + ifBody: { + let String = b.createNamedVariable(forBuiltin: "String") + splicePoint = b.indexOfNextInstruction() + b.callMethod("fromCharCode", on: String, withArgs: [i1]) + b.callMethod("fromCharCode", on: String, withArgs: [i2]) + }, + elseBody: { + b.binary(i1, i2, with: .Add) + }) let original = b.finalize() // @@ -856,9 +883,10 @@ class ProgramBuilderTests: XCTestCase { // Original Program // var i = b.loadInt(42) - b.buildDoWhileLoop(do: { - b.unary(.PostInc, i) - }, while: { b.compare(i, with: b.loadInt(44), using: .lessThan) }) + b.buildDoWhileLoop( + do: { + b.unary(.PostInc, i) + }, while: { b.compare(i, with: b.loadInt(44), using: .lessThan) }) b.loadFloat(13.37) var arr = b.createArray(with: [i, i, i]) b.getProperty("length", of: arr) @@ -923,7 +951,7 @@ class ProgramBuilderTests: XCTestCase { // // Actual Program // - let idx = original.code.lastInstruction.index - 1 // Splice at EndWhileLoop + let idx = original.code.lastInstruction.index - 1 // Splice at EndWhileLoop XCTAssert(original.code[idx].op is EndWhileLoop) b.splice(from: original, at: idx) let actual = b.finalize() @@ -1025,20 +1053,23 @@ class ProgramBuilderTests: XCTestCase { // Original Program // var n = b.loadInt(10) - var f = Variable(number: 1) // Need to declare this up front as the builder interface doesn't support recursive calls + var f = Variable(number: 1) // Need to declare this up front as the builder interface doesn't support recursive calls // The whole function is included due to the recursive call f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - b.buildIfElse(n, ifBody: { - b.unary(.PostDec, n) - let r = b.callFunction(f) - let two = b.loadInt(2) - splicePoint = b.indexOfNextInstruction() - let v = b.binary(r, two, with: .Mul) - b.doReturn(v) - }, elseBody: { - let one = b.loadInt(1) - b.doReturn(one) - }) + b.buildIfElse( + n, + ifBody: { + b.unary(.PostDec, n) + let r = b.callFunction(f) + let two = b.loadInt(2) + splicePoint = b.indexOfNextInstruction() + let v = b.binary(r, two, with: .Mul) + b.doReturn(v) + }, + elseBody: { + let one = b.loadInt(1) + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) b.callFunction(f) @@ -1056,17 +1087,20 @@ class ProgramBuilderTests: XCTestCase { n = b.loadInt(10) f = Variable(number: 1) f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - b.buildIfElse(n, ifBody: { - b.unary(.PostDec, n) - let r = b.callFunction(f) - let two = b.loadInt(2) - splicePoint = b.indexOfNextInstruction() - let v = b.binary(r, two, with: .Mul) - b.doReturn(v) - }, elseBody: { - let one = b.loadInt(1) - b.doReturn(one) - }) + b.buildIfElse( + n, + ifBody: { + b.unary(.PostDec, n) + let r = b.callFunction(f) + let two = b.loadInt(2) + splicePoint = b.indexOfNextInstruction() + let v = b.binary(r, two, with: .Mul) + b.doReturn(v) + }, + elseBody: { + let one = b.loadInt(1) + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) let expected = b.finalize() @@ -1126,10 +1160,12 @@ class ProgramBuilderTests: XCTestCase { let v = b.await(promise) let zero = b.loadInt(0) let c = b.compare(v, with: zero, using: .notEqual) - b.buildIfElse(c, ifBody: { - splicePoint = b.indexOfNextInstruction() - b.unary(.PostDec, v) - }, elseBody: {}) + b.buildIfElse( + c, + ifBody: { + splicePoint = b.indexOfNextInstruction() + b.unary(.PostDec, v) + }, elseBody: {}) } b.callFunction(f) let original = b.finalize() @@ -1167,14 +1203,16 @@ class ProgramBuilderTests: XCTestCase { // b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in let s1 = b.loadString("foo") - b.buildTryCatchFinally(tryBody: { - let s2 = b.loadString("bar") - splicePoint = b.indexOfNextInstruction() - let s3 = b.binary(s1, s2, with: .Add) - b.yield(s3) - }, catchBody: { e in - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + let s2 = b.loadString("bar") + splicePoint = b.indexOfNextInstruction() + let s3 = b.binary(s1, s2, with: .Add) + b.yield(s3) + }, + catchBody: { e in + b.yield(e) + }) let s4 = b.loadString("baz") b.yield(s4) } @@ -1210,12 +1248,14 @@ class ProgramBuilderTests: XCTestCase { let baz = b.loadString("baz") b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(foo) - b.buildTryCatchFinally(tryBody: { - b.throwException(bar) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + b.throwException(bar) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.yield(e) + }) b.yield(baz) } let original = b.finalize() @@ -1236,12 +1276,14 @@ class ProgramBuilderTests: XCTestCase { b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(b.loadInt(1337)) let bar = b.loadString("bar") - b.buildTryCatchFinally(tryBody: { - b.throwException(bar) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + b.throwException(bar) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.yield(e) + }) b.yield(b.loadInt(1338)) } let expected = b.finalize() @@ -1263,11 +1305,14 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(0) b.buildWhileLoop({ b.compare(i, with: b.loadInt(100), using: .lessThan) }) { splicePoint = b.indexOfNextInstruction() - b.buildIfElse(args[0], ifBody: { - b.yield(i) - }, elseBody: { - b.loopContinue() - }) + b.buildIfElse( + args[0], + ifBody: { + b.yield(i) + }, + elseBody: { + b.loopContinue() + }) b.unary(.PostInc, i) } } @@ -1300,11 +1345,14 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(0) b.buildWhileLoop({ b.compare(i, with: b.loadInt(100), using: .lessThan) }) { splicePoint = b.indexOfNextInstruction() - b.buildIfElse(args[0], ifBody: { - b.yield(i) - }, elseBody: { - b.loopContinue() - }) + b.buildIfElse( + args[0], + ifBody: { + b.yield(i) + }, + elseBody: { + b.loopContinue() + }) b.unary(.PostInc, i) } } @@ -1454,7 +1502,8 @@ class ProgramBuilderTests: XCTestCase { // with a function that's never called. // To test this reliably, we set the probability of remapping inner outputs to 100% but also check // that it is reasonably high by default. - XCTAssertGreaterThanOrEqual(b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing, 0.5) + XCTAssertGreaterThanOrEqual( + b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing, 0.5) b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing = 1.0 b.loadString("Foo") @@ -1481,15 +1530,18 @@ class ProgramBuilderTests: XCTestCase { let zero = b.loadInt(0) let one = b.loadInt(1) let c = b.compare(n, with: zero, using: .greaterThan) - b.buildIfElse(c, ifBody: { - let nMinusOne = b.binary(n, one, with: .Sub) - let t = b.callFunction(f, withArgs: [nMinusOne]) - splicePoint = b.indexOfNextInstruction() - let r = b.binary(n, t, with: .Mul) - b.doReturn(r) - }, elseBody: { - b.doReturn(one) - }) + b.buildIfElse( + c, + ifBody: { + let nMinusOne = b.binary(n, one, with: .Sub) + let t = b.callFunction(f, withArgs: [nMinusOne]) + splicePoint = b.indexOfNextInstruction() + let r = b.binary(n, t, with: .Mul) + b.doReturn(r) + }, + elseBody: { + b.doReturn(one) + }) } XCTAssertEqual(f.number, 0) let i = b.loadInt(42) @@ -1518,15 +1570,18 @@ class ProgramBuilderTests: XCTestCase { let zero = b.loadInt(0) let one = b.loadInt(1) let c = b.compare(n, with: zero, using: .greaterThan) - b.buildIfElse(c, ifBody: { - let nMinusOne = b.binary(n, one, with: .Sub) - let t = b.callFunction(f, withArgs: [nMinusOne]) - splicePoint = b.indexOfNextInstruction() - let r = b.binary(n, t, with: .Mul) - b.doReturn(r) - }, elseBody: { - b.doReturn(one) - }) + b.buildIfElse( + c, + ifBody: { + let nMinusOne = b.binary(n, one, with: .Sub) + let t = b.callFunction(f, withArgs: [nMinusOne]) + splicePoint = b.indexOfNextInstruction() + let r = b.binary(n, t, with: .Mul) + b.doReturn(r) + }, + elseBody: { + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) let expected = b.finalize() @@ -1673,7 +1728,7 @@ class ProgramBuilderTests: XCTestCase { // For splicing, we will not use a variable of an unknown type as replacement. let unknown = b.createNamedVariable(forBuiltin: "unknown") XCTAssertEqual(b.type(of: unknown), .jsAnything) - b.loadBool(true) // This should also never be used as replacement as it definitely has a different type + b.loadBool(true) // This should also never be used as replacement as it definitely has a different type b.splice(from: original, at: splicePoint, mergeDataFlow: true) let actual = b.finalize() @@ -1863,7 +1918,8 @@ class ProgramBuilderTests: XCTestCase { } func testClassDefinitionSplicing2() { - var splicePoint1 = -1, splicePoint2 = -1 + var splicePoint1 = -1 + var splicePoint2 = -1 let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -1963,7 +2019,10 @@ class ProgramBuilderTests: XCTestCase { // var f = b.buildPlainFunction(with: .parameters(n: 2)) { args in splicePoint = b.indexOfNextInstruction() - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) b.loopBreak() } @@ -1984,7 +2043,10 @@ class ProgramBuilderTests: XCTestCase { // f = b.buildPlainFunction(with: .parameters(n: 2)) { args in splicePoint = b.indexOfNextInstruction() - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) b.loopBreak() } @@ -1997,7 +2059,8 @@ class ProgramBuilderTests: XCTestCase { func testSplicingOfMutatingOperations() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - XCTAssertGreaterThan(b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable, 0.0) + XCTAssertGreaterThan( + b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable, 0.0) b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable = 1.0 // @@ -2014,8 +2077,10 @@ class ProgramBuilderTests: XCTestCase { b.setProperty("f", of: o, to: f2) let object = b.createNamedVariable(forBuiltin: "Object") let descriptor = b.createObject(with: ["value": b.loadString("foobar")]) - b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) - b.callMethod("defineProperty", on: object, withArgs: [o2, b.loadString("s"), descriptor]) + b.callMethod( + "defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) + b.callMethod( + "defineProperty", on: object, withArgs: [o2, b.loadString("s"), descriptor]) let json = b.createNamedVariable(forBuiltin: "JSON") b.callMethod("stringify", on: json, withArgs: [o]) } @@ -2035,12 +2100,12 @@ class ProgramBuilderTests: XCTestCase { f2 = b.loadFloat(13.37) let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included + b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included let o = b.createObject(with: ["i": i, "f": f]) - b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included + b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included let object = b.createNamedVariable(forBuiltin: "Object") let descriptor = b.createObject(with: ["value": b.loadString("foobar")]) - b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) // (Possibly) mutating instruction must be included + b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) // (Possibly) mutating instruction must be included let json = b.createNamedVariable(forBuiltin: "JSON") b.callMethod("stringify", on: json, withArgs: [o]) let expected = b.finalize() @@ -2056,7 +2121,7 @@ class ProgramBuilderTests: XCTestCase { // // Original Program // - var superclass = b.buildClassDefinition() { cls in + var superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2087,7 +2152,7 @@ class ProgramBuilderTests: XCTestCase { // // Actual Program // - superclass = b.buildClassDefinition() { cls in + superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } } @@ -2103,7 +2168,7 @@ class ProgramBuilderTests: XCTestCase { // // Expected Program // - superclass = b.buildClassDefinition() { cls in + superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } } @@ -2129,14 +2194,15 @@ class ProgramBuilderTests: XCTestCase { // b.buildAsyncGeneratorFunction(with: .parameters(n: 2)) { _ in let p = b.createNamedVariable(forBuiltin: "thePromise") - b.buildDoWhileLoop(do: { - let v0 = b.loadInt(42) - let _ = b.createObject(with: ["foo": v0]) - splicePoint = b.indexOfNextInstruction() - b.await(p) - let v8 = b.loadInt(1337) - b.yield(v8) - }, while: { b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + let v0 = b.loadInt(42) + let _ = b.createObject(with: ["foo": v0]) + splicePoint = b.indexOfNextInstruction() + b.await(p) + let v8 = b.loadInt(1337) + b.yield(v8) + }, while: { b.loadBool(false) }) } let original = b.finalize() @@ -2162,7 +2228,8 @@ class ProgramBuilderTests: XCTestCase { } func testLoopSplicing1() { - var splicePoint = -1, invalidSplicePoint = -1 + var splicePoint = -1 + var invalidSplicePoint = -1 let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -2178,12 +2245,15 @@ class ProgramBuilderTests: XCTestCase { b.buildWhileLoop({ b.compare(i2, with: end2, using: .lessThan) }) { let mid = b.binary(end2, b.loadInt(2), with: .Div) let cond = b.compare(i2, with: mid, using: .greaterThan) - b.buildIfElse(cond, ifBody: { - b.loopContinue() - }, elseBody: { - invalidSplicePoint = b.indexOfNextInstruction() - b.loopBreak() - }) + b.buildIfElse( + cond, + ifBody: { + b.loopContinue() + }, + elseBody: { + invalidSplicePoint = b.indexOfNextInstruction() + b.loopBreak() + }) b.unary(.PostInc, i2) } b.unary(.PostInc, i) @@ -2205,11 +2275,14 @@ class ProgramBuilderTests: XCTestCase { b.buildWhileLoop({ b.compare(i2, with: end2, using: .lessThan) }) { let mid = b.binary(end2, b.loadInt(2), with: .Div) let cond = b.compare(i2, with: mid, using: .greaterThan) - b.buildIfElse(cond, ifBody: { - b.loopContinue() - }, elseBody: { - b.loopBreak() - }) + b.buildIfElse( + cond, + ifBody: { + b.loopContinue() + }, + elseBody: { + b.loopBreak() + }) b.unary(.PostInc, i2) } let expected = b.finalize() @@ -2253,16 +2326,18 @@ class ProgramBuilderTests: XCTestCase { // // Original Program // - b.buildDoWhileLoop(do: { - let foo = b.createNamedVariable(forBuiltin: "foo") - b.callFunction(foo) - }, while: { - // Test that splicing out of the header works. - let bar = b.createNamedVariable(forBuiltin: "bar") - splicePoint = b.indexOfNextInstruction() - b.callFunction(bar) - return b.loadBool(false) - }) + b.buildDoWhileLoop( + do: { + let foo = b.createNamedVariable(forBuiltin: "foo") + b.callFunction(foo) + }, + while: { + // Test that splicing out of the header works. + let bar = b.createNamedVariable(forBuiltin: "bar") + splicePoint = b.indexOfNextInstruction() + b.callFunction(bar) + return b.loadBool(false) + }) let original = b.finalize() // @@ -2338,13 +2413,15 @@ class ProgramBuilderTests: XCTestCase { // Original Program // let s = b.loadString("foo") - b.buildTryCatchFinally(tryBody: { - let v = b.loadString("bar") - b.throwException(v) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.reassign(variable: e, value: s) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.loadString("bar") + b.throwException(v) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.reassign(variable: e, value: s) + }) let original = b.finalize() // @@ -2367,7 +2444,7 @@ class ProgramBuilderTests: XCTestCase { b.wasmDefineTypeGroup { let typeA = b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) let typeB = b.wasmDefineArrayType(elementType: .wasmi64, mutability: false) - splicePoint = b.indexOfNextInstruction() // the WasmEndTypeGroup + splicePoint = b.indexOfNextInstruction() // the WasmEndTypeGroup return [typeA, typeB] } let original = b.finalize() @@ -2390,14 +2467,15 @@ class ProgramBuilderTests: XCTestCase { b.wasmDefineTypeGroup { [ b.wasmDefineArrayType(elementType: .wasmi32, mutability: false), - b.wasmDefineArrayType(elementType: .wasmi64, mutability: false) + b.wasmDefineArrayType(elementType: .wasmi64, mutability: false), ] } let expected = b.finalize() - XCTAssertEqual(actual, expected, - "Actual:\n\(FuzzILLifter().lift(actual.code))\n\n" + - "Expected:\n\(FuzzILLifter().lift(expected.code))") + XCTAssertEqual( + actual, expected, + "Actual:\n\(FuzzILLifter().lift(actual.code))\n\n" + + "Expected:\n\(FuzzILLifter().lift(expected.code))") } func testCodeStringSplicing() { @@ -2410,7 +2488,7 @@ class ProgramBuilderTests: XCTestCase { // b.buildRepeatLoop(n: 5) { _ in b.loadThis() - let code = b.buildCodeString() { + let code = b.buildCodeString { let i = b.loadInt(42) let o = b.createObject(with: ["i": i]) let json = b.createNamedVariable(forBuiltin: "JSON") @@ -2431,7 +2509,7 @@ class ProgramBuilderTests: XCTestCase { // // Expected Program // - let code = b.buildCodeString() { + let code = b.buildCodeString { let i = b.loadInt(42) let o = b.createObject(with: ["i": i]) let json = b.createNamedVariable(forBuiltin: "JSON") @@ -2537,7 +2615,7 @@ class ProgramBuilderTests: XCTestCase { let variables = b.findOrGenerateArguments(forSignature: signature) XCTAssertTrue(b.type(of: variables[0]).Is(.object(ofGroup: "ArrayBuffer"))) - if (variables.count > 1) { + if variables.count > 1 { XCTAssertTrue(b.type(of: variables[1]).Is(.number)) } @@ -2568,7 +2646,8 @@ class ProgramBuilderTests: XCTestCase { let previous = b.numberOfVisibleVariables - args = b.findOrGenerateArguments(forSignature: signature2, maxNumberOfVariablesToGenerate: 1) + args = b.findOrGenerateArguments( + forSignature: signature2, maxNumberOfVariablesToGenerate: 1) XCTAssertEqual(args.count, 2) // Ensure first object has the right type, and that we only generated one more variable @@ -2579,20 +2658,29 @@ class ProgramBuilderTests: XCTestCase { func testFindOrGenerateTypeWorksRecursively() { // Types let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) - let jsD8Test = ILType.object(ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) - let jsD8FastCAPI = ILType.object(ofGroup: "D8FastCAPI", withProperties: [], withMethods: ["throw_no_fallback", "add_32bit_int"]) + let jsD8Test = ILType.object( + ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) + let jsD8FastCAPI = ILType.object( + ofGroup: "D8FastCAPI", withProperties: [], + withMethods: ["throw_no_fallback", "add_32bit_int"]) let jsD8FastCAPIConstructor = ILType.constructor([] => jsD8FastCAPI) // Object groups - let jsD8Group = ObjectGroup(name: "D8", instanceType: jsD8, properties: ["test" : jsD8Test], methods: [:]) - let jsD8TestGroup = ObjectGroup(name: "D8Test", instanceType: jsD8Test, properties: ["FastCAPI": jsD8FastCAPIConstructor], methods: [:]) - let jsD8FastCAPIGroup = ObjectGroup(name: "D8FastCAPI", instanceType: jsD8FastCAPI, properties: [:], - methods:["throw_no_fallback": [] => ILType.integer, - "add_32bit_int": [.integer, .integer] => .integer + let jsD8Group = ObjectGroup( + name: "D8", instanceType: jsD8, properties: ["test": jsD8Test], methods: [:]) + let jsD8TestGroup = ObjectGroup( + name: "D8Test", instanceType: jsD8Test, + properties: ["FastCAPI": jsD8FastCAPIConstructor], methods: [:]) + let jsD8FastCAPIGroup = ObjectGroup( + name: "D8FastCAPI", instanceType: jsD8FastCAPI, properties: [:], + methods: [ + "throw_no_fallback": [] => ILType.integer, + "add_32bit_int": [.integer, .integer] => .integer, ]) let additionalObjectGroups = [jsD8Group, jsD8TestGroup, jsD8FastCAPIGroup] - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: additionalObjectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: additionalObjectGroups) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2613,9 +2701,11 @@ class ProgramBuilderTests: XCTestCase { let objType = ILType.object(ofGroup: "Test", withProperties: [], withMethods: []) let constructor = ILType.constructor([] => objType) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["myBuiltin" : constructor], additionalObjectGroups: [testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["myBuiltin": constructor], additionalObjectGroups: [testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2631,11 +2721,14 @@ class ProgramBuilderTests: XCTestCase { let objType = ILType.object(ofGroup: "Test", withProperties: [], withMethods: []) // Object groups - let jsD8Group = ObjectGroup(name: "D8", instanceType: jsD8, properties: [:], methods: ["test" : [] => objType]) + let jsD8Group = ObjectGroup( + name: "D8", instanceType: jsD8, properties: [:], methods: ["test": [] => objType]) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: [jsD8Group, testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: [jsD8Group, testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2655,15 +2748,19 @@ class ProgramBuilderTests: XCTestCase { name: "D8", instanceType: jsD8, properties: [:], - overloads: ["test" : [ - [.string] => .integer, - [.integer, .integer] => .string, - [] => objType - ]]) + overloads: [ + "test": [ + [.string] => .integer, + [.integer, .integer] => .string, + [] => objType, + ] + ]) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: [jsD8Group, testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: [jsD8Group, testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2680,11 +2777,16 @@ class ProgramBuilderTests: XCTestCase { let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: []) let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) - let group2 = ObjectGroup(name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") - let group3 = ObjectGroup(name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") - let group4 = ObjectGroup(name: "group4", instanceType: type4, properties: [:], methods: [:], parent: "group3") + let group2 = ObjectGroup( + name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") + let group3 = ObjectGroup( + name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") + let group4 = ObjectGroup( + name: "group4", instanceType: type4, properties: [:], methods: [:], parent: "group3") - let env = JavaScriptEnvironment(additionalBuiltins: ["type3": type3], additionalObjectGroups: [group1, group2, group3, group4]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["type3": type3], + additionalObjectGroups: [group1, group2, group3, group4]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2729,35 +2831,35 @@ class ProgramBuilderTests: XCTestCase { } func testFindOrGenerateTypeWithSubtypeWithMethod() { - let type1 = ILType.object(ofGroup: "group1", withProperties: [], withMethods: []) - let type2 = ILType.object(ofGroup: "group2", withProperties: [], withMethods: []) - let type3 = ILType.object(ofGroup: "group3", withProperties: [], withMethods: []) - let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: ["method3"]) - - let type4Constructor = ILType.constructor([] => type4) - - let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) - let group2 = ObjectGroup( - name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") - let group3 = ObjectGroup( - name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") - let group4 = ObjectGroup( - name: "group4", instanceType: type4, properties: [:], - methods: [ - "method3": [] => type3 - ]) - - let env = JavaScriptEnvironment( - additionalBuiltins: ["group4": type4Constructor], - additionalObjectGroups: [group1, group2, group3, group4]) - let config = Configuration(logLevel: .error) - let fuzzer = makeMockFuzzer(config: config, environment: env) - let b = fuzzer.makeBuilder() - b.buildPrefix() - // Get a random variable and then change the type - - let obj = b.findOrGenerateType(type1) - XCTAssert(b.type(of: obj).Is(type3)) + let type1 = ILType.object(ofGroup: "group1", withProperties: [], withMethods: []) + let type2 = ILType.object(ofGroup: "group2", withProperties: [], withMethods: []) + let type3 = ILType.object(ofGroup: "group3", withProperties: [], withMethods: []) + let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: ["method3"]) + + let type4Constructor = ILType.constructor([] => type4) + + let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) + let group2 = ObjectGroup( + name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") + let group3 = ObjectGroup( + name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") + let group4 = ObjectGroup( + name: "group4", instanceType: type4, properties: [:], + methods: [ + "method3": [] => type3 + ]) + + let env = JavaScriptEnvironment( + additionalBuiltins: ["group4": type4Constructor], + additionalObjectGroups: [group1, group2, group3, group4]) + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, environment: env) + let b = fuzzer.makeBuilder() + b.buildPrefix() + // Get a random variable and then change the type + + let obj = b.findOrGenerateType(type1) + XCTAssert(b.type(of: obj).Is(type3)) } func testFindOrGenerateTypeEnum() { @@ -2778,10 +2880,10 @@ class ProgramBuilderTests: XCTestCase { analyzer.analyze() let instruction = analyzer.definition(of: obj) switch instruction.op.opcode { - case .loadString(let value): - XCTAssert(allowedValues.contains(value.value)) - default: - XCTAssert(false) + case .loadString(let value): + XCTAssert(allowedValues.contains(value.value)) + default: + XCTAssert(false) } } @@ -2795,10 +2897,11 @@ class ProgramBuilderTests: XCTestCase { } let env = JavaScriptEnvironment( - additionalBuiltins: ["foo" : .function([] => type1)], + additionalBuiltins: ["foo": .function([] => type1)], additionalObjectGroups: [group1]) let config = Configuration(logLevel: .error) - let fuzzer = makeMockFuzzer(config: config, environment: env, codeGenerators: [(testGenerator, 1)]) + let fuzzer = makeMockFuzzer( + config: config, environment: env, codeGenerators: [(testGenerator, 1)]) let b = fuzzer.makeBuilder() // Manually create a Variable, we don't want to use buildPrefix as we then might accidentally already create variable of type `type1`. @@ -2836,8 +2939,11 @@ class ProgramBuilderTests: XCTestCase { let b = fuzzer.makeBuilder() let typeGroupA = b.wasmDefineTypeGroup { - [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi64, mutability: false)], indexTypes: [])] + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi64, mutability: false)], indexTypes: []), + ] } let arrayDefI32 = typeGroupA[0] let structDef = typeGroupA[1] @@ -2938,10 +3044,14 @@ class ProgramBuilderTests: XCTestCase { let emptyMemory = b.createWasmMemory(minPages: 0) b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let (dynamicOffset, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: emptyMemory, alignment: 1) - return [function.wasmMemoryLoad(memory: emptyMemory, - dynamicOffset: dynamicOffset, loadType: .I32LoadMem, - staticOffset: staticOffset)] + let (dynamicOffset, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: emptyMemory, alignment: 1) + return [ + function.wasmMemoryLoad( + memory: emptyMemory, + dynamicOffset: dynamicOffset, loadType: .I32LoadMem, + staticOffset: staticOffset) + ] } } } @@ -2950,9 +3060,12 @@ class ProgramBuilderTests: XCTestCase { let emptyMemory = b.createWasmMemory(minPages: 0) b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - return [function.wasmMemoryLoad(memory: emptyMemory, - dynamicOffset: function.consti32(0), loadType: .I32LoadMem, - staticOffset: 0)] + return [ + function.wasmMemoryLoad( + memory: emptyMemory, + dynamicOffset: function.consti32(0), loadType: .I32LoadMem, + staticOffset: 0) + ] } } } @@ -3003,13 +3116,14 @@ class ProgramBuilderTests: XCTestCase { let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - if case .wasmMemorySize = instr.op.opcode { - return true - } else { - return false - } - })) + XCTAssertTrue( + program.code.contains(where: { instr in + if case .wasmMemorySize = instr.op.opcode { + return true + } else { + return false + } + })) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } @@ -3037,8 +3151,10 @@ class ProgramBuilderTests: XCTestCase { let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: N) XCTAssertGreaterThan(numGeneratedInstructions, 0) // All generator input requirements are fulfilled. - XCTAssert(generator.parts.allSatisfy { - $0.inputs.constraints.allSatisfy { b.randomVariable(ofType: $0.type) != nil }}) + XCTAssert( + generator.parts.allSatisfy { + $0.inputs.constraints.allSatisfy { b.randomVariable(ofType: $0.type) != nil } + }) // All generator `produces` guarantees are fulfilled. XCTAssert(generator.produces.allSatisfy { b.randomVariable(ofType: $0.type) != nil }) let _ = b.finalize() @@ -3054,10 +3170,13 @@ class ProgramBuilderTests: XCTestCase { b.buildPrefix() // TODO(mliedtke): The mechanism needs to learn how to resolve nested input dependencies. - b.wasmDefineTypeGroup {[ - b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), - ]} + b.wasmDefineTypeGroup { + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), + ] + } let generator = fuzzer.codeGenerators.filter { $0.name == "WasmArrayGetGenerator" @@ -3067,27 +3186,30 @@ class ProgramBuilderTests: XCTestCase { let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) XCTAssertNotNil(syntheticGenerator) - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) + let numGeneratedInstructions = b.complete( + generator: syntheticGenerator!, withBudget: 30) let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - switch instr.op.opcode { + XCTAssertTrue( + program.code.contains(where: { instr in + switch instr.op.opcode { case .wasmArrayGet(_): return true default: return false - } - })) + } + })) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } func testWasmGCScheduling() { func test( - _ generatorName: String, - expectAny: repeat (each ExpectedOp).Type, - requiresTypes: Bool = false) { + _ generatorName: String, + expectAny: repeat (each ExpectedOp).Type, + requiresTypes: Bool = false + ) { let fuzzer = makeMockFuzzer() let numPrograms = 30 @@ -3098,25 +3220,30 @@ class ProgramBuilderTests: XCTestCase { // TODO(mliedtke): The mechanism needs to learn how to resolve nested input + // context dependencies. if requiresTypes { - b.wasmDefineTypeGroup {[ - b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), - ]} + b.wasmDefineTypeGroup { + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), + ] + } } - let generator = fuzzer.codeGenerators.filter {$0.name == generatorName}[0] + let generator = fuzzer.codeGenerators.filter { $0.name == generatorName }[0] let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) XCTAssertNotNil(syntheticGenerator) - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) + let numGeneratedInstructions = b.complete( + generator: syntheticGenerator!, withBudget: 30) let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - for match in repeat instr.op is (each ExpectedOp) { - if match { return true } - } - return false - }), generatorName) + XCTAssertTrue( + program.code.contains(where: { instr in + for match in repeat instr.op is (each ExpectedOp) { + if match { return true } + } + return false + }), generatorName) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } @@ -3139,7 +3266,8 @@ class ProgramBuilderTests: XCTestCase { b.buildPrefix() if let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) { - let generatedInstructions = b.complete(generator: syntheticGenerator, withBudget: 40) + let generatedInstructions = b.complete( + generator: syntheticGenerator, withBudget: 40) if generatedInstructions == 0 { failures[generator.name, default: 0] += 1 @@ -3175,20 +3303,22 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { } func testNested() { - let loopGenerator = CodeGenerator("TestDoWhileLoop", [ - GeneratorStub("BeginLoop") { b in - let loopVar = b.loadInt(0) - b.runtimeData.push("loopVar", loopVar) - b.emit(BeginDoWhileLoopBody()) - }, - GeneratorStub("EndLoop") { b in - let loopVar = b.runtimeData.pop("loopVar") - b.unary(.PreInc, loopVar) - b.emit(BeginDoWhileLoopHeader()) - let cond = b.compare(loopVar, with: b.loadInt(3), using: .lessThan) - b.emit(EndDoWhileLoop(), withInputs: [cond]) - } - ]) + let loopGenerator = CodeGenerator( + "TestDoWhileLoop", + [ + GeneratorStub("BeginLoop") { b in + let loopVar = b.loadInt(0) + b.runtimeData.push("loopVar", loopVar) + b.emit(BeginDoWhileLoopBody()) + }, + GeneratorStub("EndLoop") { b in + let loopVar = b.runtimeData.pop("loopVar") + b.unary(.PreInc, loopVar) + b.emit(BeginDoWhileLoopHeader()) + let cond = b.compare(loopVar, with: b.loadInt(3), using: .lessThan) + b.emit(EndDoWhileLoop(), withInputs: [cond]) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(loopGenerator), """ @@ -3206,23 +3336,25 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { func testMultiLabel() { var counter: Int64 = 0 - let defineAndAddGenerator = CodeGenerator("TestMultiLabel", [ - GeneratorStub("Define") { b in - b.runtimeData.push("first", b.loadInt(counter)) - counter += 1 - b.runtimeData.push("second", b.loadInt(counter)) - counter += 1 - b.runtimeData.push("third", b.loadInt(counter)) - counter += 1 - }, - GeneratorStub("Add") { b in - // The order in which the different lables are popped doesn't matter. - let third = b.runtimeData.pop("third") - let first = b.runtimeData.pop("first") - let second = b.runtimeData.pop("second") - b.binary(b.binary(first, second, with: .Add), third, with: .Add) - } - ]) + let defineAndAddGenerator = CodeGenerator( + "TestMultiLabel", + [ + GeneratorStub("Define") { b in + b.runtimeData.push("first", b.loadInt(counter)) + counter += 1 + b.runtimeData.push("second", b.loadInt(counter)) + counter += 1 + b.runtimeData.push("third", b.loadInt(counter)) + counter += 1 + }, + GeneratorStub("Add") { b in + // The order in which the different lables are popped doesn't matter. + let third = b.runtimeData.pop("third") + let first = b.runtimeData.pop("first") + let second = b.runtimeData.pop("second") + b.binary(b.binary(first, second, with: .Add), third, with: .Add) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(defineAndAddGenerator), """ @@ -3234,22 +3366,24 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { func testPassOn() { var counter: Int64 = 10 - let defineAndAddGenerator = CodeGenerator("TestPassOn", [ - GeneratorStub("Define") { b in - let value = b.loadInt(counter) - b.runtimeData.push("value", value) - b.binary(value, b.loadInt(0), with: .Add) - counter += 1 - }, - GeneratorStub("AddOne") { b in - let value = b.runtimeData.peek("value") - b.binary(value, b.loadInt(1), with: .Add) - }, - GeneratorStub("SubOne") { b in - let value = b.runtimeData.pop("value") - b.binary(value, b.loadInt(1), with: .Sub) - }, - ]) + let defineAndAddGenerator = CodeGenerator( + "TestPassOn", + [ + GeneratorStub("Define") { b in + let value = b.loadInt(counter) + b.runtimeData.push("value", value) + b.binary(value, b.loadInt(0), with: .Add) + counter += 1 + }, + GeneratorStub("AddOne") { b in + let value = b.runtimeData.peek("value") + b.binary(value, b.loadInt(1), with: .Add) + }, + GeneratorStub("SubOne") { b in + let value = b.runtimeData.pop("value") + b.binary(value, b.loadInt(1), with: .Sub) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(defineAndAddGenerator), """ diff --git a/Tests/FuzzilliTests/ProgramSerializationTest.swift b/Tests/FuzzilliTests/ProgramSerializationTest.swift index 9cbceaa49..65b2e5164 100644 --- a/Tests/FuzzilliTests/ProgramSerializationTest.swift +++ b/Tests/FuzzilliTests/ProgramSerializationTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli func testAndCompareSerialization(program: Program) { @@ -81,10 +82,10 @@ class ProgramSerializationTests: XCTestCase { b.append(Instruction(complexOp, output: b.nextVariable(), inputs: [v(2), v(3)])) let program = b.finalize() - XCTAssert(program.code[0].op === program.code[2].op && - program.code[0].op === program.code[4].op) - XCTAssert(program.code[5].op === program.code[7].op && - program.code[5].op === program.code[9].op) + XCTAssert( + program.code[0].op === program.code[2].op && program.code[0].op === program.code[4].op) + XCTAssert( + program.code[5].op === program.code[7].op && program.code[5].op === program.code[9].op) let encodingCache = OperationCache.forEncoding() let decodingCache = OperationCache.forDecoding() @@ -96,10 +97,8 @@ class ProgramSerializationTests: XCTestCase { XCTAssertEqual(program, copy) XCTAssert(copy.code[0].op !== program.code[0].op) - XCTAssert(copy.code[0].op === copy.code[2].op && - copy.code[0].op === copy.code[4].op) - XCTAssert(copy.code[5].op === copy.code[7].op && - copy.code[5].op === copy.code[9].op) + XCTAssert(copy.code[0].op === copy.code[2].op && copy.code[0].op === copy.code[4].op) + XCTAssert(copy.code[5].op === copy.code[7].op && copy.code[5].op === copy.code[9].op) } // As our equality operation is based on the protobuf representation, we do these tests here. diff --git a/Tests/FuzzilliTests/RingBufferTest.swift b/Tests/FuzzilliTests/RingBufferTest.swift index a23abc7dd..702c0e950 100644 --- a/Tests/FuzzilliTests/RingBufferTest.swift +++ b/Tests/FuzzilliTests/RingBufferTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class RingBufferTests: XCTestCase { diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift index 4d1182b96..4b2eb9e34 100644 --- a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class RuntimeAssistedMutatorTests: XCTestCase { @@ -21,10 +22,14 @@ class RuntimeAssistedMutatorTests: XCTestCase { var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { // Minimization can change quotation marks. Checking for both here to be on the safe side. - if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") { - return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") + || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") + { + return MockExecution( + outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } else { - return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + return MockExecution( + outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } } func setEnvironmentVariable(_ key: String, to value: String) {} @@ -45,7 +50,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on processed program") + let crashEventTriggered = self.expectation( + description: "Crash reported on processed program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let lifted = fuzzer.lifter.lift(ev.program) if lifted.contains("This is the processed program") { @@ -69,7 +75,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + let crashEventTriggered = self.expectation( + description: "Crash reported on instrumented program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let lifted = fuzzer.lifter.lift(ev.program) if !lifted.contains("This is the processed program") { @@ -83,15 +90,22 @@ class RuntimeAssistedMutatorTests: XCTestCase { // This test checks that if *only* the instrumented program crashes, this program is minimized. - func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { - guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { - throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + throw XCTSkip( + "Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } // Initialize the parser. This can fail if no node.js executable is found or if the // parser's node.js dependencies are not installed. In that case, skip these tests. guard JavaScriptParser(executor: nodejs) != nil else { - throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + throw XCTSkip( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } class CrashEvaluator: MockEvaluator { @@ -116,13 +130,15 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + let crashEventTriggered = self.expectation( + description: "Crash reported on instrumented program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let actualProgram = ev.program - XCTAssertEqual(expectedProgram, actualProgram, - "The reported program should be the minimized version of the instrumented program.\n" + - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "The reported program should be the minimized version of the instrumented program.\n" + + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") crashEventTriggered.fulfill() } diff --git a/Tests/FuzzilliTests/ScriptWriterTest.swift b/Tests/FuzzilliTests/ScriptWriterTest.swift index ac816db6e..b4f6d5235 100644 --- a/Tests/FuzzilliTests/ScriptWriterTest.swift +++ b/Tests/FuzzilliTests/ScriptWriterTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ScriptWriterTest: XCTestCase { @@ -21,17 +22,17 @@ class ScriptWriterTest: XCTestCase { var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 10) w.emit("My name is Ozymandias, king of kings. Look on my works, ye Mighty, and despair!") let expected = """ - My name is - Ozymandias - , king of - kings. - Look on my - works, ye - Mighty, - and - despair! + My name is + Ozymandias + , king of + kings. + Look on my + works, ye + Mighty, + and + despair! - """ + """ XCTAssertEqual(expected, w.code) } @@ -46,39 +47,39 @@ class ScriptWriterTest: XCTestCase { w.emit("and despair!") w.decreaseIndentionLevel() let expected = """ - My name - is - Ozymandi - as, - king - of - kings. - Look on - my - works, - ye - Mighty, - and - despai - r! + My name + is + Ozymandi + as, + king + of + kings. + Look on + my + works, + ye + Mighty, + and + despai + r! - """ + """ XCTAssertEqual(expected, w.code) } func testLineSplittingMultiSpace() { - var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 8) - let str = (0...10).map {"\($0)\(String(repeating: " ", count: $0))"}.joined() - w.emit(str) - let expected = """ - 01 2 3 - 4 5 - 6 7 - 8 - 9 - 10 + var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 8) + let str = (0...10).map { "\($0)\(String(repeating: " ", count: $0))" }.joined() + w.emit(str) + let expected = """ + 01 2 3 + 4 5 + 6 7 + 8 + 9 + 10 - """ - XCTAssertEqual(expected, w.code) + """ + XCTAssertEqual(expected, w.code) } } diff --git a/Tests/FuzzilliTests/TestUtils.swift b/Tests/FuzzilliTests/TestUtils.swift index 414d1fbfa..0928898bb 100644 --- a/Tests/FuzzilliTests/TestUtils.swift +++ b/Tests/FuzzilliTests/TestUtils.swift @@ -14,6 +14,7 @@ import Foundation import XCTest + @testable import Fuzzilli extension Program: @retroactive Equatable { @@ -49,20 +50,27 @@ func v(_ n: Int) -> Variable { func GetJavaScriptExecutorOrSkipTest() throws -> JavaScriptExecutor { guard let runner = JavaScriptExecutor() else { - throw XCTSkip("Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable).") + throw XCTSkip( + "Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable)." + ) } return runner } -func GetJavaScriptExecutorOrSkipTest(type: JavaScriptExecutor.ExecutorType, withArguments args: [String]) throws -> JavaScriptExecutor { +func GetJavaScriptExecutorOrSkipTest( + type: JavaScriptExecutor.ExecutorType, withArguments args: [String] +) throws -> JavaScriptExecutor { guard let runner = JavaScriptExecutor(type: type, withArguments: args) else { - throw XCTSkip("Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable).") + throw XCTSkip( + "Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable)." + ) } return runner } - -func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (ProgramBuilder) -> ()) -> String { +func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (ProgramBuilder) -> Void) + -> String +{ let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -75,13 +83,14 @@ func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (Program // AssertThat prog == Deserialize(Serilize(prog)) let prog = b.finalize() let serializedBytes = try! prog.asProtobuf().serializedData() - let deserialized = try! Program(from: Fuzzilli_Protobuf_Program(serializedBytes: serializedBytes)) + let deserialized = try! Program( + from: Fuzzilli_Protobuf_Program(serializedBytes: serializedBytes)) XCTAssertEqual(prog, deserialized) return fuzzer.lifter.lift(prog, withOptions: withLiftingOptions) } -func buildAndLiftProgram(buildFunc: (ProgramBuilder) -> ()) -> String { +func buildAndLiftProgram(buildFunc: (ProgramBuilder) -> Void) -> String { return buildAndLiftProgram(withLiftingOptions: [], buildFunc: buildFunc) } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 677032925..91f17cdb2 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class TypeSystemTests: XCTestCase { @@ -28,7 +29,8 @@ class TypeSystemTests: XCTestCase { for t2 in typeSuite { for t3 in typeSuite { if t1 >= t2 && t2 >= t3 { - XCTAssert(t1 >= t3, "\(t1) >= \(t2) && \(t2) >= \(t3) implies \(t1) => \(t3)") + XCTAssert( + t1 >= t3, "\(t1) >= \(t2) && \(t2) >= \(t3) implies \(t1) => \(t3)") } } } @@ -41,7 +43,8 @@ class TypeSystemTests: XCTestCase { if t1 >= t2 && t2 >= t1 { XCTAssert(t1 == t2, "\(t1) >= \(t2) && \(t2) >= \(t1) implies \(t1) == \(t2)") } else if t1 >= t2 { - XCTAssertFalse(t2 >= t1, "\(t1) >= \(t2) && \(t1) != \(t2) implies \(t2) !>= \(t1)") + XCTAssertFalse( + t2 >= t1, "\(t1) >= \(t2) && \(t1) != \(t2) implies \(t2) !>= \(t1)") } } } @@ -62,7 +65,9 @@ class TypeSystemTests: XCTestCase { XCTAssert(.object(withMethods: ["m1"]) != .object()) XCTAssert(.function() == .function()) - XCTAssert(.function([.integer, .rest(.integer)] => .undefined) == .function([.integer, .rest(.integer)] => .undefined)) + XCTAssert( + .function([.integer, .rest(.integer)] => .undefined) + == .function([.integer, .rest(.integer)] => .undefined)) XCTAssert(.function([.integer, .rest(.integer)] => .undefined) != .function()) // Test equality properties for all types in the test suite @@ -72,7 +77,9 @@ class TypeSystemTests: XCTestCase { XCTAssert(t1 >= t2, "\(t1) == \(t2) implies \(t1) >= \(t2)") XCTAssert(t2 >= t1, "\(t1) == \(t2) implies \(t2) >= \(t1)") } else { - XCTAssertFalse(t1 >= t2 && t2 >= t1, "\(t1) != \(t2) implies !(\(t1) >= \(t2) && \(t2) >= \(t1))") + XCTAssertFalse( + t1 >= t2 && t2 >= t1, + "\(t1) != \(t2) implies !(\(t1) >= \(t2) && \(t2) >= \(t1))") } } } @@ -118,8 +125,10 @@ class TypeSystemTests: XCTestCase { // assumes the function has the signature of f2). // See also the signature subsumption test for more complicated examples. XCTAssert(ILType.function([.jsAnything] => .integer).Is(.function([.integer] => .number))) - XCTAssertFalse(ILType.function([.integer] => .integer).Is(.function([.jsAnything] => .number))) - XCTAssertFalse(ILType.function([.jsAnything] => .number).Is(.function([.jsAnything] => .integer))) + XCTAssertFalse( + ILType.function([.integer] => .integer).Is(.function([.jsAnything] => .number))) + XCTAssertFalse( + ILType.function([.jsAnything] => .number).Is(.function([.jsAnything] => .integer))) for t1 in typeSuite { for t2 in typeSuite { @@ -132,7 +141,8 @@ class TypeSystemTests: XCTestCase { } if t2.Is(t1) { - XCTAssertFalse(t2.MayNotBe(t1), "(\(t2)).Is(\(t1)) <=> !((\(t2)).MayNotBe(\(t1)))") + XCTAssertFalse( + t2.MayNotBe(t1), "(\(t2)).Is(\(t1)) <=> !((\(t2)).MayNotBe(\(t1)))") XCTAssert(t1 >= t2, "\(t1) >= \(t2) <=> (\(t2)).Is(\(t1))") } else { XCTAssertFalse(t1 >= t2, "\(t1) >= \(t2) <=> (\(t2)).Is(\(t1))") @@ -162,10 +172,13 @@ class TypeSystemTests: XCTestCase { // The way to think about is is (probably) that a function taking .jsAnything may still be called // with a .integer as argument. However, from a practical point of view the function that takes .integer // may in fact also be fine with a different argument. - XCTAssert(ILType.function([.integer] => .jsAnything).MayBe(.function([.jsAnything] => .jsAnything))) + XCTAssert( + ILType.function([.integer] => .jsAnything).MayBe( + .function([.jsAnything] => .jsAnything))) // But (at least from a theoretical point-of-view) a function taking a .integer is definitely not a function // that takes (only) a string as first parameter. - XCTAssertFalse(ILType.function([.integer] => .jsAnything).MayBe(.function([.string] => .jsAnything))) + XCTAssertFalse( + ILType.function([.integer] => .jsAnything).MayBe(.function([.string] => .jsAnything))) XCTAssert((ILType.integer | ILType.boolean).MayBe(ILType.integer | ILType.string)) XCTAssertFalse((ILType.integer + ILType.object()).MayBe(ILType.string + ILType.object())) @@ -195,16 +208,19 @@ class TypeSystemTests: XCTestCase { if t1 & t2 != .nothing { XCTAssert(t2.MayBe(t1), "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") } else { - XCTAssertFalse(t2.MayBe(t1), "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") + XCTAssertFalse( + t2.MayBe(t1), "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") } XCTAssert((t1 | t2).MayBe(t1), "A union type may be one of its parts") XCTAssert((t1 | t2).MayBe(t2), "A union type may be one of its parts") if t2.MayBe(t1) { - XCTAssert(t1 & t2 != .nothing, "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") + XCTAssert( + t1 & t2 != .nothing, "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") } else { - XCTAssert(t1 & t2 == .nothing, "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") + XCTAssert( + t1 & t2 == .nothing, "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") } } } @@ -277,7 +293,9 @@ class TypeSystemTests: XCTestCase { // E.g. string objects never subsume objects, but can subsume other string objects if the // properties and methods are a subset. if t1.baseType == t2.baseType && (t1.group == nil || t1.group == t2.group) { - if t1.properties.isSubset(of: t2.properties) && t1.methods.isSubset(of: t2.methods) && t1.wasmType == t2.wasmType { + if t1.properties.isSubset(of: t2.properties) + && t1.methods.isSubset(of: t2.methods) && t1.wasmType == t2.wasmType + { XCTAssert(t1 >= t2, "\(t1) >= \(t2)") } } @@ -316,8 +334,10 @@ class TypeSystemTests: XCTestCase { let fooObj = ILType.object(withProperties: fooProperties, withMethods: fooMethods) let barObj = ILType.object(withProperties: barProperties, withMethods: barMethods) let bazObj = ILType.object(withProperties: bazProperties, withMethods: bazMethods) - let fooBarObj = ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods) - let fooBazObj = ILType.object(withProperties: fooBazProperties, withMethods: fooBazMethods) + let fooBarObj = ILType.object( + withProperties: fooBarProperties, withMethods: fooBarMethods) + let fooBazObj = ILType.object( + withProperties: fooBazProperties, withMethods: fooBazMethods) // Foo, Bar, Baz, FooBar, and FooBaz objects are all objects, but not every object is a Foo, Bar, Baz, FooBar, or FooBaz object. XCTAssert(object >= fooObj) @@ -332,10 +352,22 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(fooBazObj >= object) // Order of property and methods names does not matter. - XCTAssert(fooBarObj >= ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) - XCTAssert(fooBarObj >= ILType.object(withProperties: fooBarProperties.reversed(), withMethods: fooBarMethods.reversed())) - XCTAssert(fooBarObj == ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) - XCTAssert(fooBarObj == ILType.object(withProperties: fooBarProperties.reversed(), withMethods: fooBarMethods.reversed())) + XCTAssert( + fooBarObj + >= ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) + XCTAssert( + fooBarObj + >= ILType.object( + withProperties: fooBarProperties.reversed(), + withMethods: fooBarMethods.reversed())) + XCTAssert( + fooBarObj + == ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) + XCTAssert( + fooBarObj + == ILType.object( + withProperties: fooBarProperties.reversed(), + withMethods: fooBarMethods.reversed())) // No subsumption relationship between Foo, Bar, and Baz objects XCTAssertFalse(fooObj >= barObj) @@ -405,7 +437,9 @@ class TypeSystemTests: XCTestCase { let fooBarBazProperties = fooProperties + barProperties + bazProperties let fooBarBazMethods = fooMethods + barMethods + bazMethods XCTAssert(fooObj + barObj + bazObj == fooBarObj + fooBazObj) - XCTAssert(fooBarObj + fooBazObj == .object(withProperties: fooBarBazProperties, withMethods: fooBarBazMethods)) + XCTAssert( + fooBarObj + fooBazObj + == .object(withProperties: fooBarBazProperties, withMethods: fooBarBazMethods)) } } @@ -494,9 +528,17 @@ class TypeSystemTests: XCTestCase { // Repeat the below tests for functions, constructors, and function constructors (function and constructor at the same time) // We call something that is a function or a constructor (or both) a "callable". - let anyCallables = [ILType.function(), ILType.constructor(), ILType.functionAndConstructor()] - let callable1s = [ILType.function(signature1), ILType.constructor(signature1), ILType.functionAndConstructor(signature1)] - let callable2s = [ILType.function(signature2), ILType.constructor(signature2), ILType.functionAndConstructor(signature2)] + let anyCallables = [ + ILType.function(), ILType.constructor(), ILType.functionAndConstructor(), + ] + let callable1s = [ + ILType.function(signature1), ILType.constructor(signature1), + ILType.functionAndConstructor(signature1), + ] + let callable2s = [ + ILType.function(signature2), ILType.constructor(signature2), + ILType.functionAndConstructor(signature2), + ] for i in 0..<3 { let anyCallable = anyCallables[i] @@ -558,13 +600,16 @@ class TypeSystemTests: XCTestCase { } func testWasmGlobalSubsumption() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmi64Mutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmi64Mutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: true) - let ILTypeGlobalI32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalI64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) + let ILTypeGlobalI32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalI64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) XCTAssert(ILTypeGlobalI32Mutable >= ILTypeGlobalI32Mutable) // Types which don't have equal WasmTypeExtension don't subsume. @@ -574,9 +619,12 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(ILTypeGlobalI64Mutable >= ILTypeGlobalI32Mutable) XCTAssertFalse(ILTypeGlobalI32NonMutable >= ILTypeGlobalI64Mutable) - let ILTypeGlobalI32MutableNoGroup: ILType = ILType.object(withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32MutableNoProperty: ILType = ILType.object(ofGroup: "WasmGlobal", withWasmType: wasmi32Mutable) - let ILTypeGlobalI32MutableNoWasmType: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"]) + let ILTypeGlobalI32MutableNoGroup: ILType = ILType.object( + withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32MutableNoProperty: ILType = ILType.object( + ofGroup: "WasmGlobal", withWasmType: wasmi32Mutable) + let ILTypeGlobalI32MutableNoWasmType: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"]) let ILTypeGlobalOnlyGroup: ILType = ILType.object(ofGroup: "WasmGlobal") let ILTypeGlobalOnlyProperty: ILType = ILType.object(withProperties: ["value"]) @@ -594,19 +642,23 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(ILTypeGlobalI32Mutable >= ILTypeGlobalOnlyProperty) // Groups should match. - let ILTypeWrongGroup = ILType.object(ofGroup: "SomeOtherGroup", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeWrongGroup = ILType.object( + ofGroup: "SomeOtherGroup", withProperties: ["value"], withWasmType: wasmi32Mutable) XCTAssertFalse(ILTypeWrongGroup >= ILTypeGlobalI32Mutable) XCTAssertFalse(ILTypeGlobalI32Mutable >= ILTypeWrongGroup) } func testWasmGlobalUnion() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmf32Mutable = WasmGlobalType(valueType:ILType.wasmf32, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmf32Mutable = WasmGlobalType(valueType: ILType.wasmf32, isMutable: true) - let ILTypeGlobalI32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalF32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf32Mutable) + let ILTypeGlobalI32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalF32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf32Mutable) XCTAssertEqual(ILTypeGlobalI32Mutable | ILTypeGlobalI32Mutable, ILTypeGlobalI32Mutable) @@ -628,34 +680,46 @@ class TypeSystemTests: XCTestCase { // .wasmGlobalType extension.) XCTAssertEqual(ILTypeGlobalI32Mutable | .object(ofGroup: "WasmGlobal"), .object()) XCTAssert(.object(ofGroup: "WasmGlobal") >= ILTypeGlobalI32Mutable) - XCTAssertEqual(ILTypeGlobalI32Mutable | .object(withProperties: ["value"]), .object(withProperties: ["value"])) + XCTAssertEqual( + ILTypeGlobalI32Mutable | .object(withProperties: ["value"]), + .object(withProperties: ["value"])) XCTAssert(.object(withProperties: ["value"]) >= ILTypeGlobalI32Mutable) } func testWasmGlobalIntersection() { - let wasmi64Mutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: true) - let wasmi64NonMutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: false) - let wasmf64Mutable = WasmGlobalType(valueType:ILType.wasmf64, isMutable: true) + let wasmi64Mutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: true) + let wasmi64NonMutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: false) + let wasmf64Mutable = WasmGlobalType(valueType: ILType.wasmf64, isMutable: true) - let ILTypeGlobalI64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) - let ILTypeGlobalI64NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64NonMutable) - let ILTypeGlobalF64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) + let ILTypeGlobalI64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) + let ILTypeGlobalI64NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64NonMutable) + let ILTypeGlobalF64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalI64Mutable, ILTypeGlobalI64Mutable) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalI64NonMutable, .nothing) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalF64Mutable, .nothing) - XCTAssertEqual(ILTypeGlobalI64Mutable & .object(withProperties: ["value"]), ILTypeGlobalI64Mutable) - XCTAssertEqual((ILTypeGlobalI64Mutable & ILType.object(withWasmType: wasmi64Mutable)), ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable)) + XCTAssertEqual( + ILTypeGlobalI64Mutable & .object(withProperties: ["value"]), ILTypeGlobalI64Mutable) + XCTAssertEqual( + (ILTypeGlobalI64Mutable & ILType.object(withWasmType: wasmi64Mutable)), + ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable)) } func testWasmGlobalIsAndMayBe() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmf64Mutable = WasmGlobalType(valueType:ILType.wasmf64, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmf64Mutable = WasmGlobalType(valueType: ILType.wasmf64, isMutable: true) - let ILTypeGlobalI32Mutable: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalF64Mutable: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) + let ILTypeGlobalI32Mutable: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalF64Mutable: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) XCTAssert(ILTypeGlobalI32Mutable.Is(.object(ofGroup: "WasmGlobal"))) XCTAssert(ILTypeGlobalI32Mutable.Is(.object(withProperties: ["value"]))) @@ -686,7 +750,7 @@ class TypeSystemTests: XCTestCase { XCTAssert(.integer | .float | .string >= .string) XCTAssert(.integer | .float | .string >= .integer | .float) XCTAssert(.integer | .float | .string >= .integer | .string) - XCTAssert(.integer | .float | .string >= .float | .string) + XCTAssert(.integer | .float | .string >= .float | .string) XCTAssert(.integer | .float | .string >= .integer | .float | .string) XCTAssert(.integer | .float | .string == .integer | .float | .string) @@ -715,13 +779,14 @@ class TypeSystemTests: XCTestCase { for t2 in primitiveTypes { for t3 in primitiveTypes { if t3 != t1 && t3 != t2 { - XCTAssertFalse(t1 | t2 >= t3, "\(t3) != \(t1) && \(t3) != \(t2) => \(t1) | \(t2) !>= \(t3)") + XCTAssertFalse( + t1 | t2 >= t3, + "\(t3) != \(t1) && \(t3) != \(t2) => \(t1) | \(t2) !>= \(t3)") } } } } - for t1 in typeSuite { XCTAssert(t1 | t1 == t1, "\(t1) | \(t1) (\(t1 | t1)) == \(t1)") @@ -787,12 +852,19 @@ class TypeSystemTests: XCTestCase { // Maybe a bit less intuitively, the intersection of two functions with different signatures can also exist. // In the following example, the more general signature of the two functions is the intersection as that's what // both functions "have in common". - XCTAssertEqual(ILType.function([.jsAnything] => .integer) & .function([.integer] => .jsAnything), .function([.jsAnything] => .integer)) - XCTAssertEqual(ILType.function([.jsAnything] => .jsAnything) & .function([.integer] => .jsAnything), .function([.jsAnything] => .jsAnything)) + XCTAssertEqual( + ILType.function([.jsAnything] => .integer) & .function([.integer] => .jsAnything), + .function([.jsAnything] => .integer)) + XCTAssertEqual( + ILType.function([.jsAnything] => .jsAnything) & .function([.integer] => .jsAnything), + .function([.jsAnything] => .jsAnything)) // In this example, the parameter type is widened and the return type is narrowed. - XCTAssertEqual(ILType.function([.integer] => .integer) & .function([.jsAnything] => .jsAnything), .function([.jsAnything] => .integer)) + XCTAssertEqual( + ILType.function([.integer] => .integer) & .function([.jsAnything] => .jsAnything), + .function([.jsAnything] => .integer)) // However, here the return types are incompatible - XCTAssertEqual(ILType.function([.integer] => .integer) & .function([.integer] => .string), .nothing) + XCTAssertEqual( + ILType.function([.integer] => .integer) & .function([.integer] => .string), .nothing) // Now test the basic invariants of intersections for all types in the type suite. for t1 in typeSuite { @@ -800,7 +872,8 @@ class TypeSystemTests: XCTestCase { for t2 in typeSuite { // Intersecting is symmetric - XCTAssert(t1 & t2 == t2 & t1, "\(t1) & \(t2) (\(t2 & t2)) == \(t2) & \(t1) (\(t2 & t1))") + XCTAssert( + t1 & t2 == t2 & t1, "\(t1) & \(t2) (\(t2 & t2)) == \(t2) & \(t1) (\(t2 & t1))") let intersection = t1 & t2 @@ -810,7 +883,8 @@ class TypeSystemTests: XCTestCase { // If one of the two inputs subsumes the other, then the result will be the subsumed type. if t1 >= t2 { - XCTAssert(t1 & t2 == t2, "\(t1) >= \(t2) => \(t1) & \(t2) (\(t1 & t2)) == \(t2)") + XCTAssert( + t1 & t2 == t2, "\(t1) >= \(t2) => \(t1) & \(t2) (\(t1 & t2)) == \(t2)") } } } @@ -851,12 +925,17 @@ class TypeSystemTests: XCTestCase { for t3 in typeSuite { if t3 >= t1 || t3 >= t2 { // If t1 or t2 are a t3, than the merged type t1 + t2 must also be a t3. - XCTAssert(t3 >= merged, "\(t3) >= \(t1) || \(t3) >= \(t2) implies \(t3) >= \(t1) + \(t2) (\(merged))") + XCTAssert( + t3 >= merged, + "\(t3) >= \(t1) || \(t3) >= \(t2) implies \(t3) >= \(t1) + \(t2) (\(merged))" + ) } guard t1.canMerge(with: t3) && t2.canMerge(with: t3) else { continue } if t1 >= t2 { - XCTAssert(t1 + t3 >= t2 + t3, "\(t1) >= \(t2) implies \(t1) + \(t3) >= \(t2) + \(t3)") + XCTAssert( + t1 + t3 >= t2 + t3, + "\(t1) >= \(t2) implies \(t1) + \(t3) >= \(t2) + \(t3)") } } } @@ -876,11 +955,15 @@ class TypeSystemTests: XCTestCase { } // Callables with different signatures cannot be merged - else if t1.isCallable && t2.isCallable && t1.signature != nil && t2.signature != nil && t1.signature != t2.signature { + else if t1.isCallable && t2.isCallable && t1.signature != nil && t2.signature != nil + && t1.signature != t2.signature + { XCTAssertFalse(t1.canMerge(with: t2)) } - else if t1.isCallable && t2.isCallable && t1.receiver != nil && t2.receiver != nil && t1.receiver != t2.receiver { + else if t1.isCallable && t2.isCallable && t1.receiver != nil && t2.receiver != nil + && t1.receiver != t2.receiver + { XCTAssertFalse(t1.canMerge(with: t2)) } @@ -935,7 +1018,8 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse([.integer, .integer] => .undefined >= [.integer, .string] => .undefined) // Or, phrased differentley still, a function that accepts anything as first // parameter is a function that accepts an integer as first parameter. - XCTAssert(ILType.function([.jsAnything] => .undefined).Is(.function([.integer] => .undefined))) + XCTAssert( + ILType.function([.jsAnything] => .undefined).Is(.function([.integer] => .undefined))) // However, the other direction does not hold: if we want a function that // accepts anything as first parameter, we cannot use a function that // requires an integer as first parameter instead. @@ -976,9 +1060,11 @@ class TypeSystemTests: XCTestCase { XCTAssert([] => .undefined >= [.opt(.integer), .opt(.float)] => .undefined) XCTAssert([.opt(.integer)] => .undefined >= [.opt(.jsAnything)] => .undefined) XCTAssert([.opt(.integer)] => .undefined >= [] => .undefined) - XCTAssert([.string, .opt(.integer)] => .undefined >= [.string, .jsAnything...] => .undefined) + XCTAssert( + [.string, .opt(.integer)] => .undefined >= [.string, .jsAnything...] => .undefined) XCTAssert([.integer] => .undefined >= [.opt(.integer)] => .undefined) - XCTAssertFalse([.integer, .integer] => .undefined >= [.opt(.integer), .opt(.string)] => .undefined) + XCTAssertFalse( + [.integer, .integer] => .undefined >= [.opt(.integer), .opt(.string)] => .undefined) XCTAssertFalse([.opt(.integer)] => .undefined >= [.integer] => .undefined) XCTAssertFalse([.opt(.integer)] => .undefined >= [.string...] => .undefined) XCTAssertFalse([.string...] => .undefined >= [.opt(.integer)] => .undefined) @@ -1002,24 +1088,40 @@ class TypeSystemTests: XCTestCase { // Previously we would just say that all objects are the same anyways. // Now we want them to be interchangeable, e.g. for splicing in JS. XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object0").Is(.object(ofGroup: "_fuzz_Object1"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_WasmExports0").Is(.object(ofGroup: "_fuzz_WasmExports1"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_WasmModule0").Is(.object(ofGroup: "_fuzz_WasmModule1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_WasmExports0").Is(.object(ofGroup: "_fuzz_WasmExports1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_WasmModule0").Is(.object(ofGroup: "_fuzz_WasmModule1"))) XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Constructor0"))) - - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Constructor1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Constructor0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Class0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Constructor1"))) // Negative tests to make sure they don't subsume if they don't subsume based on properties / methods.. - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object1", withMethods: ["a"]).Is(.object(ofGroup: "_fuzz_Object0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Object1").Is(.object(ofGroup: "_fuzz_Object0", withMethods: ["a"]))) - - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Class1", withProperties: ["a"]).Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) - - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"]).Is(.object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["b"]).Is(.object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Object1", withMethods: ["a"]).Is( + .object(ofGroup: "_fuzz_Object0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Object1").Is( + .object(ofGroup: "_fuzz_Object0", withMethods: ["a"]))) + + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Class1", withProperties: ["a"]).Is( + .object(ofGroup: "_fuzz_Class0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Class1").Is( + .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) + + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"]).Is( + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["b"]).Is( + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) } @@ -1047,34 +1149,68 @@ class TypeSystemTests: XCTestCase { // Test object types XCTAssertEqual(ILType.object().description, ".object()") - XCTAssertEqual(ILType.object(withProperties: ["foo"]).description, ".object(withProperties: [\"foo\"])") - XCTAssertEqual(ILType.object(withMethods: ["m"]).description, ".object(withMethods: [\"m\"])") + XCTAssertEqual( + ILType.object(withProperties: ["foo"]).description, ".object(withProperties: [\"foo\"])" + ) + XCTAssertEqual( + ILType.object(withMethods: ["m"]).description, ".object(withMethods: [\"m\"])") // Property and method order is not defined let fooBarObj = ILType.object(withProperties: ["foo", "bar"]) - XCTAssert(fooBarObj.description == ".object(withProperties: [\"foo\", \"bar\"])" || fooBarObj.description == ".object(withProperties: [\"bar\", \"foo\"])") + XCTAssert( + fooBarObj.description == ".object(withProperties: [\"foo\", \"bar\"])" + || fooBarObj.description == ".object(withProperties: [\"bar\", \"foo\"])") let objWithMethods = ILType.object(withMethods: ["m1", "m2"]) - XCTAssert(objWithMethods.description == ".object(withMethods: [\"m1\", \"m2\"])" || objWithMethods.description == ".object(withMethods: [\"m2\", \"m1\"])") + XCTAssert( + objWithMethods.description == ".object(withMethods: [\"m1\", \"m2\"])" + || objWithMethods.description == ".object(withMethods: [\"m2\", \"m1\"])") let fooBarObjWithMethod = ILType.object(withProperties: ["foo", "bar"], withMethods: ["m"]) - XCTAssert(fooBarObjWithMethod.description == ".object(withProperties: [\"foo\", \"bar\"], withMethods: [\"m\"])" || fooBarObjWithMethod.description == ".object(withProperties: [\"bar\", \"foo\"], withMethods: [\"m\"])") + XCTAssert( + fooBarObjWithMethod.description + == ".object(withProperties: [\"foo\", \"bar\"], withMethods: [\"m\"])" + || fooBarObjWithMethod.description + == ".object(withProperties: [\"bar\", \"foo\"], withMethods: [\"m\"])" + ) // Test function and constructor types XCTAssertEqual(ILType.function().description, ".function()") - XCTAssertEqual(ILType.function([.rest(.jsAnything)] => .jsAnything).description, ".function([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.function([.float, .opt(.integer)] => .object()).description, ".function([.float, .opt(.integer)] => .object())") - XCTAssertEqual(ILType.function([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".function([.integer, .boolean, .jsAnything...] => .object())") + XCTAssertEqual( + ILType.function([.rest(.jsAnything)] => .jsAnything).description, + ".function([.jsAnything...] => .jsAnything)") + XCTAssertEqual( + ILType.function([.float, .opt(.integer)] => .object()).description, + ".function([.float, .opt(.integer)] => .object())") + XCTAssertEqual( + ILType.function([.integer, .boolean, .rest(.jsAnything)] => .object()).description, + ".function([.integer, .boolean, .jsAnything...] => .object())") XCTAssertEqual(ILType.constructor().description, ".constructor()") - XCTAssertEqual(ILType.constructor([.rest(.jsAnything)] => .jsAnything).description, ".constructor([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.constructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".constructor([.integer, .boolean, .jsAnything...] => .object())") + XCTAssertEqual( + ILType.constructor([.rest(.jsAnything)] => .jsAnything).description, + ".constructor([.jsAnything...] => .jsAnything)") + XCTAssertEqual( + ILType.constructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, + ".constructor([.integer, .boolean, .jsAnything...] => .object())") XCTAssertEqual(ILType.functionAndConstructor().description, ".function() + .constructor()") - XCTAssertEqual(ILType.functionAndConstructor([.rest(.jsAnything)] => .jsAnything).description, ".function([.jsAnything...] => .jsAnything) + .constructor([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.functionAndConstructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".function([.integer, .boolean, .jsAnything...] => .object()) + .constructor([.integer, .boolean, .jsAnything...] => .object())") - - XCTAssertEqual(ILType.unboundFunction([.integer, .boolean, .rest(.jsAnything)] => .object(), receiver: .object()).description, ".unboundFunction([.integer, .boolean, .jsAnything...] => .object(), receiver: .object())") + XCTAssertEqual( + ILType.functionAndConstructor([.rest(.jsAnything)] => .jsAnything).description, + ".function([.jsAnything...] => .jsAnything) + .constructor([.jsAnything...] => .jsAnything)" + ) + XCTAssertEqual( + ILType.functionAndConstructor([.integer, .boolean, .rest(.jsAnything)] => .object()) + .description, + ".function([.integer, .boolean, .jsAnything...] => .object()) + .constructor([.integer, .boolean, .jsAnything...] => .object())" + ) + + XCTAssertEqual( + ILType.unboundFunction( + [.integer, .boolean, .rest(.jsAnything)] => .object(), receiver: .object() + ).description, + ".unboundFunction([.integer, .boolean, .jsAnything...] => .object(), receiver: .object())" + ) XCTAssertEqual(ILType.unboundFunction().description, ".unboundFunction(nil, receiver: nil)") // Test other "well-known" types @@ -1100,15 +1236,31 @@ class TypeSystemTests: XCTestCase { let strObj = ILType.string + ILType.object(withProperties: ["foo"]) XCTAssertEqual(strObj.description, ".string + .object(withProperties: [\"foo\"])") - let funcObj = ILType.object(withProperties: ["foo"], withMethods: ["m"]) + ILType.function([.integer, .rest(.jsAnything)] => .boolean) - XCTAssertEqual(funcObj.description, ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean)") - - let funcConstrObj = ILType.object(withProperties: ["foo"], withMethods: ["m"]) + ILType.functionAndConstructor([.integer, .rest(.jsAnything)] => .boolean) - XCTAssertEqual(funcConstrObj.description, ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean) + .constructor([.integer, .jsAnything...] => .boolean)") + let funcObj = + ILType.object(withProperties: ["foo"], withMethods: ["m"]) + + ILType.function([.integer, .rest(.jsAnything)] => .boolean) + XCTAssertEqual( + funcObj.description, + ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean)" + ) + + let funcConstrObj = + ILType.object(withProperties: ["foo"], withMethods: ["m"]) + + ILType.functionAndConstructor([.integer, .rest(.jsAnything)] => .boolean) + XCTAssertEqual( + funcConstrObj.description, + ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean) + .constructor([.integer, .jsAnything...] => .boolean)" + ) // Test union of merged types - let strObjOrFuncObj = (ILType.string + ILType.object(withProperties: ["foo"])) | (ILType.function([.rest(.jsAnything)] => .float) + ILType.object(withProperties: ["foo"])) - XCTAssertEqual(strObjOrFuncObj.description, ".string + .object(withProperties: [\"foo\"]) | .object(withProperties: [\"foo\"]) + .function()") + let strObjOrFuncObj = + (ILType.string + ILType.object(withProperties: ["foo"])) + | (ILType.function([.rest(.jsAnything)] => .float) + + ILType.object(withProperties: ["foo"])) + XCTAssertEqual( + strObjOrFuncObj.description, + ".string + .object(withProperties: [\"foo\"]) | .object(withProperties: [\"foo\"]) + .function()" + ) let nullExn = ILType.wasmRef(.WasmExn, shared: true, nullability: true) let nonNullAny = ILType.wasmRef(.WasmAny, shared: false, nullability: false) @@ -1116,44 +1268,55 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(nonNullAny.description, ".wasmRef(.Abstract(WasmAny))") // TODO(pawkra): add shared variant. - let arrayDesc = WasmArrayTypeDescription(elementType: .wasmi32, mutability: false, typeGroupIndex: 0) + let arrayDesc = WasmArrayTypeDescription( + elementType: .wasmi32, mutability: false, typeGroupIndex: 0) let arrayRef = ILType.wasmIndexRef(arrayDesc, nullability: true) XCTAssertEqual(arrayRef.description, ".wasmRef(null Index 0 Array[immutable .wasmi32])") - let nullableSelfRef = ILType.wasmRef(.Index(.init(WasmTypeDescription.selfReference)), nullability: true) - let structDesc = WasmStructTypeDescription(fields: [ - .init(type: .wasmf32, mutability: true), - .init(type: nullableSelfRef, mutability: false), // unresolved - .init(type: arrayRef, mutability: true) - ], typeGroupIndex: 1) + let nullableSelfRef = ILType.wasmRef( + .Index(.init(WasmTypeDescription.selfReference)), nullability: true) + let structDesc = WasmStructTypeDescription( + fields: [ + .init(type: .wasmf32, mutability: true), + .init(type: nullableSelfRef, mutability: false), // unresolved + .init(type: arrayRef, mutability: true), + ], typeGroupIndex: 1) let structRef = ILType.wasmIndexRef(structDesc, nullability: false) - XCTAssertEqual(structRef.description, - ".wasmRef(Index 1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index selfReference), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structRef.description, + ".wasmRef(Index 1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index selfReference), mutable .wasmRef(null Index 0 Array)])" + ) // Create a cycle (a "resolved" self reference) for an array element type. arrayDesc.elementType = arrayRef - XCTAssertEqual(arrayRef.description, + XCTAssertEqual( + arrayRef.description, ".wasmRef(null Index 0 Array[immutable .wasmRef(null Index 0 Array)])") // Create a cycle for a struct field type. structDesc.fields[1].type = .wasmIndexRef(structDesc, nullability: true) - XCTAssertEqual(structRef.description, - ".wasmRef(Index 1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structRef.description, + ".wasmRef(Index 1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") // Type definitions print the same thing as references just with .wasmTypeDef instead of // .wasmRef. let arrayDef = ILType.wasmTypeDef(description: arrayDesc) - XCTAssertEqual(arrayDef.description, + XCTAssertEqual( + arrayDef.description, ".wasmTypeDef(0 Array[immutable .wasmRef(null Index 0 Array)])") let structDef = ILType.wasmTypeDef(description: structDesc) - XCTAssertEqual(structDef.description, - ".wasmTypeDef(1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structDef.description, + ".wasmTypeDef(1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") let signatureDesc = WasmSignatureTypeDescription( - signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef(shared: true)], typeGroupIndex: 0) + signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef(shared: true)], + typeGroupIndex: 0) let signatureDef = ILType.wasmTypeDef(description: signatureDesc) - XCTAssertEqual(signatureDef.description, - ".wasmTypeDef(0 Func[[.wasmi32, .wasmRef(null Index 0 Array)] => " + - "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null shared WasmNone))]])") + XCTAssertEqual( + signatureDef.description, + ".wasmTypeDef(0 Func[[.wasmi32, .wasmRef(null Index 0 Array)] => " + + "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null shared WasmNone))]])") // A generic index type without a type description. // These are e.g. used by the element types for arrays and structs inside the operation as @@ -1164,7 +1327,8 @@ class TypeSystemTests: XCTestCase { } func testWasmSubsumptionRules() { - let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allNullableAbstractWasmRefTypes() + let wasmTypes: [ILType] = + [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allNullableAbstractWasmRefTypes() // Make sure that no Wasm type is subsumed by (JS-)anything. for t in wasmTypes { XCTAssertEqual(t <= .jsAnything, false) @@ -1172,38 +1336,60 @@ class TypeSystemTests: XCTestCase { } func testWasmTypeExtensionSubsumptionRules() { - let arrayi32Desc = WasmArrayTypeDescription(elementType: .wasmi32, mutability: true, typeGroupIndex: 0) - let arrayi64Desc = WasmArrayTypeDescription(elementType: .wasmi64, mutability: true, typeGroupIndex: 0) + let arrayi32Desc = WasmArrayTypeDescription( + elementType: .wasmi32, mutability: true, typeGroupIndex: 0) + let arrayi64Desc = WasmArrayTypeDescription( + elementType: .wasmi64, mutability: true, typeGroupIndex: 0) // Test Wasm reference type definitions. XCTAssertNotEqual(ILType.wasmTypeDef(), ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertNotEqual(ILType.wasmTypeDef(description: arrayi64Desc), - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertEqual(ILType.wasmTypeDef(description: arrayi32Desc), - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssert(ILType.wasmTypeDef(description:arrayi32Desc) <= ILType.wasmTypeDef()) - XCTAssert(ILType.wasmTypeDef(description: arrayi32Desc) <= - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertFalse(ILType.wasmTypeDef(description: arrayi32Desc) <= - ILType.wasmTypeDef(description: arrayi64Desc)) + XCTAssertNotEqual( + ILType.wasmTypeDef(description: arrayi64Desc), + ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssertEqual( + ILType.wasmTypeDef(description: arrayi32Desc), + ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssert(ILType.wasmTypeDef(description: arrayi32Desc) <= ILType.wasmTypeDef()) + XCTAssert( + ILType.wasmTypeDef(description: arrayi32Desc) + <= ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssertFalse( + ILType.wasmTypeDef(description: arrayi32Desc) + <= ILType.wasmTypeDef(description: arrayi64Desc)) // Test Wasm references. - XCTAssert(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmRef(.Index(), nullability: true)) - XCTAssert(ILType.wasmRef(.Index(), nullability: false) <= ILType.wasmRef(.Index(), nullability: false)) - XCTAssert(ILType.wasmRef(.Index(), nullability: false) <= ILType.wasmRef(.Index(), nullability: true)) - XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmRef(.Index(), nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmRef(.Index(), nullability: true)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: false) + <= ILType.wasmRef(.Index(), nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: false) + <= ILType.wasmRef(.Index(), nullability: true)) + XCTAssertFalse( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmRef(.Index(), nullability: false)) XCTAssertFalse(ILType.wasmi32 <= ILType.wasmRef(.Index(), nullability: true)) XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmi32) - XCTAssertFalse(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi64Desc, nullability: true)) - XCTAssertFalse(ILType.wasmIndexRef(arrayi64Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssert(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssert(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: false)) - XCTAssert(ILType.wasmRef(.Index(), nullability: true) >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi64Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmIndexRef(arrayi64Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssert( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssert( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) XCTAssert(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmGenericRef) XCTAssertFalse(ILType.wasmGenericRef <= ILType.wasmRef(.Index(), nullability: true)) @@ -1254,10 +1440,10 @@ class TypeSystemTests: XCTestCase { XCTAssert(WasmAbstractHeapType.allCases.allSatisfy(allTypes.contains)) // All types in the same type group share the same bottom type. - XCTAssert(groupAny.allSatisfy {$0.getBottom() == .WasmNone}) - XCTAssert(groupExtern.allSatisfy {$0.getBottom() == .WasmNoExtern}) - XCTAssert(groupFunc.allSatisfy {$0.getBottom() == .WasmNoFunc}) - XCTAssert(groupExn.allSatisfy {$0.getBottom() == .WasmNoExn}) + XCTAssert(groupAny.allSatisfy { $0.getBottom() == .WasmNone }) + XCTAssert(groupExtern.allSatisfy { $0.getBottom() == .WasmNoExtern }) + XCTAssert(groupFunc.allSatisfy { $0.getBottom() == .WasmNoFunc }) + XCTAssert(groupExn.allSatisfy { $0.getBottom() == .WasmNoExn }) // The union and intersection of of two unrelated types are nil. for groupA in allGroups { @@ -1290,8 +1476,10 @@ class TypeSystemTests: XCTestCase { // Tests on the whole ILType. for shared in [true, false] { - let ref: (WasmAbstractHeapType) -> ILType = {t in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t in ILType.wasmRef(t, shared: shared, nullability: true)} + let ref: (WasmAbstractHeapType) -> ILType = { t in + ILType.wasmRef(t, shared: shared, nullability: false, ) + } + let refNull = { t in ILType.wasmRef(t, shared: shared, nullability: true) } for type in allTypes { let refT = ref(type) @@ -1314,20 +1502,23 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(ref(.WasmI31).union(with: refNull(.WasmExn)), .wasmGenericRef) XCTAssertEqual(ref(.WasmAny).intersection(with: refNull(.WasmEq)), ref(.WasmEq)) - XCTAssertEqual(refNull(.WasmI31).intersection(with: refNull(.WasmStruct)), refNull(.WasmNone)) + XCTAssertEqual( + refNull(.WasmI31).intersection(with: refNull(.WasmStruct)), refNull(.WasmNone)) // Note that `ref none` is a perfectly valid type in Wasm but such a reference can never be // constructed. XCTAssertEqual(ref(.WasmArray).intersection(with: refNull(.WasmStruct)), ref(.WasmNone)) XCTAssertEqual(refNull(.WasmArray).intersection(with: ref(.WasmAny)), ref(.WasmArray)) } - let ref = {t, shared in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t, shared in ILType.wasmRef(t, shared: shared, nullability: true)} + let ref = { t, shared in ILType.wasmRef(t, shared: shared, nullability: false, ) } + let refNull = { t, shared in ILType.wasmRef(t, shared: shared, nullability: true) } // Shared and unshared ref hierarchies are disjoint. for (lhsShared, rhsShared) in [(true, false), (false, true)] { for type in allTypes { - XCTAssertEqual(ref(type, lhsShared).union(with: ref(type, rhsShared)), .wasmGenericRef) - XCTAssertEqual(refNull(type, lhsShared).union(with: refNull(type, rhsShared)), .wasmGenericRef) + XCTAssertEqual( + ref(type, lhsShared).union(with: ref(type, rhsShared)), .wasmGenericRef) + XCTAssertEqual( + refNull(type, lhsShared).union(with: refNull(type, rhsShared)), .wasmGenericRef) } } } @@ -1338,8 +1529,10 @@ class TypeSystemTests: XCTestCase { XCTAssertNotEqual(ILType.unboundFunction(receiver: .object()), .unboundFunction()) XCTAssert(ILType.unboundFunction(receiver: .object()).Is(.unboundFunction())) XCTAssertFalse(ILType.unboundFunction().Is(.unboundFunction(receiver: .object()))) - XCTAssert(ILType.unboundFunction(receiver: .object()).Is(.unboundFunction(receiver: .jsAnything))) - XCTAssertFalse(ILType.unboundFunction(receiver: .jsAnything).Is(.unboundFunction(receiver: .object()))) + XCTAssert( + ILType.unboundFunction(receiver: .object()).Is(.unboundFunction(receiver: .jsAnything))) + XCTAssertFalse( + ILType.unboundFunction(receiver: .jsAnything).Is(.unboundFunction(receiver: .object()))) let receiverNil = ILType.unboundFunction() let receiverObject = ILType.unboundFunction(receiver: .object()) @@ -1355,102 +1548,109 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(receiverObject.intersection(with: receiverNil), receiverObject) } - let primitiveTypes: [ILType] = [.undefined, .integer, .float, .string, .boolean, .bigint, .regexp] + let primitiveTypes: [ILType] = [ + .undefined, .integer, .float, .string, .boolean, .bigint, .regexp, + ] // A set of different types used by various tests. // TODO(cffsmith): Test and adjust types with a WasmTypeExtension. - let typeSuite: [ILType] = [.undefined, - .integer, - .float, - .string, - .boolean, - .bigint, - .regexp, - .iterable, - .jsAnything, - .nothing, - .object(), - .object(ofGroup: "A"), - .object(ofGroup: "B"), - .object(withProperties: ["foo"]), - .object(withProperties: ["bar"]), - .object(withProperties: ["baz"]), - .object(withProperties: ["foo", "bar"]), - .object(withProperties: ["foo", "baz"]), - .object(withProperties: ["foo", "bar", "baz"]), - .object(withMethods: ["m1"]), - .object(withMethods: ["m2"]), - .object(withMethods: ["m1", "m2"]), - .object(withProperties: ["foo"], withMethods: ["m1"]), - .object(withProperties: ["foo"], withMethods: ["m2"]), - .object(withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(withProperties: ["baz"], withMethods: ["m1"]), - .object(withProperties: ["bar"], withMethods: ["m1", "m2"]), - .object(withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .object(withProperties: ["foo", "bar", "baz"], withMethods: ["m1", "m2"]), - .object(ofGroup: "A", withProperties: ["foo"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"]), - .object(ofGroup: "A", withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .object(ofGroup: "B", withProperties: ["foo"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"]), - .object(ofGroup: "B", withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo"], withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .function(), - .function([.string] => .string), - .function([.string] => .jsAnything), - .function([.primitive] => .string), - .function([.string, .string] => .jsAnything), - .function([.integer] => .number), - .function([.jsAnything...] => .jsAnything), - .function([.integer, .string, .opt(.jsAnything)] => .float), - .unboundFunction(), - .unboundFunction([.string] => .string), - .unboundFunction([.string] => .string, receiver: .object()), - .unboundFunction([.string] => .jsAnything, receiver: .object()), - .constructor(), - .constructor([.string] => .string), - .constructor([.string] => .jsAnything), - .constructor([.primitive] => .string), - .constructor([.string, .string] => .jsAnything), - .constructor([.integer] => .number), - .constructor([.jsAnything...] => .object()), - .constructor([.integer, .string, .opt(.jsAnything)] => .object()), - .functionAndConstructor(), - .functionAndConstructor([.string] => .string), - .functionAndConstructor([.string] => .jsAnything), - .functionAndConstructor([.primitive] => .string), - .functionAndConstructor([.string, .string] => .jsAnything), - .functionAndConstructor([.integer] => .number), - .functionAndConstructor([.jsAnything...] => .jsAnything), - .functionAndConstructor([.integer, .string, .opt(.jsAnything)] => .object()), - .number, - .primitive, - .string | .object(), - .string | .object(withProperties: ["foo"]), - .object(withProperties: ["foo"]) | .function(), - .object(withProperties: ["foo"]) | .constructor([.rest(.jsAnything)] => .object()), - .primitive | .object() | .function() | .constructor(), - .string + .object(withProperties: ["foo", "bar"]), - .integer + .object(withProperties: ["foo"], withMethods: ["m"]), - .object(withProperties: ["foo", "bar"]) + .function([.integer] => .jsAnything), - .object(ofGroup: "A", withProperties: ["foo", "bar"]) + .constructor([.integer] => .jsAnything), - .object(withMethods: ["m1"]) + .functionAndConstructor([.integer, .boolean] => .jsAnything), - .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]) + .functionAndConstructor([.integer, .boolean] => .jsAnything), - // Wasm types - .wasmAnything, - .wasmi32, - .wasmf32, - .wasmi64, - .wasmf64, - .wasmFunctionDef([.wasmi32] => [.wasmi64]), - .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), - .wasmMemory(limits: Limits(min: 10)), - .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + ILType.allNullableAbstractWasmRefTypes() + let typeSuite: [ILType] = + [ + .undefined, + .integer, + .float, + .string, + .boolean, + .bigint, + .regexp, + .iterable, + .jsAnything, + .nothing, + .object(), + .object(ofGroup: "A"), + .object(ofGroup: "B"), + .object(withProperties: ["foo"]), + .object(withProperties: ["bar"]), + .object(withProperties: ["baz"]), + .object(withProperties: ["foo", "bar"]), + .object(withProperties: ["foo", "baz"]), + .object(withProperties: ["foo", "bar", "baz"]), + .object(withMethods: ["m1"]), + .object(withMethods: ["m2"]), + .object(withMethods: ["m1", "m2"]), + .object(withProperties: ["foo"], withMethods: ["m1"]), + .object(withProperties: ["foo"], withMethods: ["m2"]), + .object(withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(withProperties: ["baz"], withMethods: ["m1"]), + .object(withProperties: ["bar"], withMethods: ["m1", "m2"]), + .object(withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .object(withProperties: ["foo", "bar", "baz"], withMethods: ["m1", "m2"]), + .object(ofGroup: "A", withProperties: ["foo"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"]), + .object(ofGroup: "A", withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .object(ofGroup: "B", withProperties: ["foo"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"]), + .object(ofGroup: "B", withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo"], withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .function(), + .function([.string] => .string), + .function([.string] => .jsAnything), + .function([.primitive] => .string), + .function([.string, .string] => .jsAnything), + .function([.integer] => .number), + .function([.jsAnything...] => .jsAnything), + .function([.integer, .string, .opt(.jsAnything)] => .float), + .unboundFunction(), + .unboundFunction([.string] => .string), + .unboundFunction([.string] => .string, receiver: .object()), + .unboundFunction([.string] => .jsAnything, receiver: .object()), + .constructor(), + .constructor([.string] => .string), + .constructor([.string] => .jsAnything), + .constructor([.primitive] => .string), + .constructor([.string, .string] => .jsAnything), + .constructor([.integer] => .number), + .constructor([.jsAnything...] => .object()), + .constructor([.integer, .string, .opt(.jsAnything)] => .object()), + .functionAndConstructor(), + .functionAndConstructor([.string] => .string), + .functionAndConstructor([.string] => .jsAnything), + .functionAndConstructor([.primitive] => .string), + .functionAndConstructor([.string, .string] => .jsAnything), + .functionAndConstructor([.integer] => .number), + .functionAndConstructor([.jsAnything...] => .jsAnything), + .functionAndConstructor([.integer, .string, .opt(.jsAnything)] => .object()), + .number, + .primitive, + .string | .object(), + .string | .object(withProperties: ["foo"]), + .object(withProperties: ["foo"]) | .function(), + .object(withProperties: ["foo"]) | .constructor([.rest(.jsAnything)] => .object()), + .primitive | .object() | .function() | .constructor(), + .string + .object(withProperties: ["foo", "bar"]), + .integer + .object(withProperties: ["foo"], withMethods: ["m"]), + .object(withProperties: ["foo", "bar"]) + .function([.integer] => .jsAnything), + .object(ofGroup: "A", withProperties: ["foo", "bar"]) + + .constructor([.integer] => .jsAnything), + .object(withMethods: ["m1"]) + + .functionAndConstructor([.integer, .boolean] => .jsAnything), + .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]) + + .functionAndConstructor([.integer, .boolean] => .jsAnything), + // Wasm types + .wasmAnything, + .wasmi32, + .wasmf32, + .wasmi64, + .wasmf64, + .wasmFunctionDef([.wasmi32] => [.wasmi64]), + .wasmFunctionDef([.wasmf32] => [.wasmi32]), + .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), + .wasmMemory(limits: Limits(min: 10)), + .wasmMemory(limits: Limits(min: 10, max: 20)), + ] + ILType.allNullableAbstractWasmRefTypes() } diff --git a/Tests/FuzzilliTests/VariableMapTest.swift b/Tests/FuzzilliTests/VariableMapTest.swift index 9dbbca9b2..98da6ecf0 100644 --- a/Tests/FuzzilliTests/VariableMapTest.swift +++ b/Tests/FuzzilliTests/VariableMapTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class VariableMapTests: XCTestCase { @@ -105,7 +106,7 @@ class VariableMapTests: XCTestCase { for i in 0..<1000 { withProbability(0.75) { - map[v(i)] = Int.random(in: 0..<1000000) + map[v(i)] = Int.random(in: 0..<1_000_000) } } @@ -124,7 +125,7 @@ class VariableMapTests: XCTestCase { for i in 0..<1000 { withProbability(0.75) { - let value = Int.random(in: 0..<1000000) + let value = Int.random(in: 0..<1_000_000) map1[v(i)] = value map2[v(i)] = value } @@ -138,7 +139,7 @@ class VariableMapTests: XCTestCase { var map = VariableMap() for i in 0..<1000 { withProbability(0.5) { - map[v(i)] = Int.random(in: 0..<1000000) + map[v(i)] = Int.random(in: 0..<1_000_000) } } @@ -172,7 +173,7 @@ class VariableMapTests: XCTestCase { for i in 0.. [.wasmi32]) { f, _, _ in let valueToStore = f.consti32(1337) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i32Store, offset: 0) - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i32Store, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load, offset: 0) return [loadedValue] } } @@ -40,10 +44,13 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in - let valueToStore = f.consti64(0x1122334455667788) + let valueToStore = f.consti64(0x1122_3344_5566_7788) let address = f.consti32(16) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i64Store, offset: 0) - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i64Store, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load, offset: 0) return [loadedValue] } } @@ -83,12 +90,15 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { f, _, _ in // The store will wrap this to 0xFF - let valueToStore = f.consti32(0x123456FF) + let valueToStore = f.consti32(0x1234_56FF) let address = f.consti32(4) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i32Store8, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i32Store8, offset: 0) // The load will zero-extend 0xFF to 255 - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load8U, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load8U, offset: 0) return [loadedValue] } } @@ -97,12 +107,15 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in // The store will wrap this to 0xEF - let valueToStore = f.consti64(0x1234567890ABCDEF) + let valueToStore = f.consti64(0x1234_5678_90AB_CDEF) let address = f.consti32(4) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i64Store8, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i64Store8, offset: 0) // The load will zero-extend 0xEF to 239 - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load8U, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load8U, offset: 0) return [loadedValue] } } @@ -138,9 +151,10 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(1) // Unaligned for 4-byte access + let address = f.consti32(1) // Unaligned for 4-byte access // This should trap. - f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load, offset: 0) + f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load, offset: 0) return [] } } @@ -148,9 +162,10 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(4) // Unaligned for 8-byte access + let address = f.consti32(4) // Unaligned for 8-byte access // This should trap. - f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load, offset: 0) + f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load, offset: 0) return [] } } @@ -159,10 +174,12 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(2) // Unaligned for 4-byte access + let address = f.consti32(2) // Unaligned for 4-byte access // This should trap. let value = f.consti32(0x1337) - f.wasmAtomicStore(memory: memory, address: address, value: value, storeType: .i32Store, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: value, storeType: .i32Store, + offset: 0) return [] } } @@ -170,10 +187,12 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(7) // Unaligned for 8-byte access + let address = f.consti32(7) // Unaligned for 8-byte access // This should trap. - let value = f.consti64(0xDEADBEEF) - f.wasmAtomicStore(memory: memory, address: address, value: value, storeType: .i64Store, offset: 0) + let value = f.consti64(0xDEAD_BEEF) + f.wasmAtomicStore( + memory: memory, address: address, value: value, storeType: .i64Store, + offset: 0) return [] } } @@ -202,26 +221,27 @@ class WasmAtomicsTests: XCTestCase { var expectedResults: [String] = [] let js = buildAndLiftProgram { b in - let testCases: [( - op: WasmAtomicRMWType, - storeType: WasmAtomicStoreType, - loadType: WasmAtomicLoadType, - valueType: ILType - )] = - [.i32Add, .i32Sub, .i32And, .i32Or, .i32Xor, .i32Xchg] - .map { ($0, .i32Store, .i32Load, .wasmi32) } + - [.i32Add8U, .i32Sub8U, .i32And8U, .i32Or8U, .i32Xor8U, .i32Xchg8U] - .map { ($0, .i32Store8, .i32Load8U, .wasmi32) } + - [.i32Add16U, .i32Sub16U, .i32And16U, .i32Or16U, .i32Xor16U, .i32Xchg16U] - .map { ($0, .i32Store16, .i32Load16U, .wasmi32) } + - [.i64Add, .i64Sub, .i64And, .i64Or, .i64Xor, .i64Xchg] - .map { ($0, .i64Store, .i64Load, .wasmi64) } + - [.i64Add8U, .i64Sub8U, .i64And8U, .i64Or8U, .i64Xor8U, .i64Xchg8U] - .map { ($0, .i64Store8, .i64Load8U, .wasmi64) } + - [.i64Add16U, .i64Sub16U, .i64And16U, .i64Or16U, .i64Xor16U, .i64Xchg16U] - .map { ($0, .i64Store16, .i64Load16U, .wasmi64) } + - [.i64Add32U, .i64Sub32U, .i64And32U, .i64Or32U, .i64Xor32U, .i64Xchg32U] - .map { ($0, .i64Store32, .i64Load32U, .wasmi64) } + let testCases: + [( + op: WasmAtomicRMWType, + storeType: WasmAtomicStoreType, + loadType: WasmAtomicLoadType, + valueType: ILType + )] = + [.i32Add, .i32Sub, .i32And, .i32Or, .i32Xor, .i32Xchg] + .map { ($0, .i32Store, .i32Load, .wasmi32) } + + [.i32Add8U, .i32Sub8U, .i32And8U, .i32Or8U, .i32Xor8U, .i32Xchg8U] + .map { ($0, .i32Store8, .i32Load8U, .wasmi32) } + + [.i32Add16U, .i32Sub16U, .i32And16U, .i32Or16U, .i32Xor16U, .i32Xchg16U] + .map { ($0, .i32Store16, .i32Load16U, .wasmi32) } + + [.i64Add, .i64Sub, .i64And, .i64Or, .i64Xor, .i64Xchg] + .map { ($0, .i64Store, .i64Load, .wasmi64) } + + [.i64Add8U, .i64Sub8U, .i64And8U, .i64Or8U, .i64Xor8U, .i64Xchg8U] + .map { ($0, .i64Store8, .i64Load8U, .wasmi64) } + + [.i64Add16U, .i64Sub16U, .i64And16U, .i64Or16U, .i64Xor16U, .i64Xchg16U] + .map { ($0, .i64Store16, .i64Load16U, .wasmi64) } + + [.i64Add32U, .i64Sub32U, .i64And32U, .i64Or32U, .i64Xor32U, .i64Xchg32U] + .map { ($0, .i64Store32, .i64Load32U, .wasmi64) } let initialValue: Int64 = 12 let operand: Int64 = 10 @@ -233,30 +253,46 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { for (op, storeType, loadType, valueType) in testCases { let returnType = valueType - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) - let rhs = (valueType == .wasmi32) ? f.consti32(Int32(operand)) : f.consti64(operand) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + let rhs = + (valueType == .wasmi32) + ? f.consti32(Int32(operand)) : f.consti64(operand) let lhs = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: lhs, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicRMW(memory: memory, lhs: lhs, rhs: rhs, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: lhs, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: lhs, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicRMW( + memory: memory, lhs: lhs, rhs: rhs, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: lhs, loadType: loadType, offset: 0) return [originalValue, finalValue] } - let expectedFinal = switch op { - case .i32Add, .i32Add8U, .i32Add16U, .i64Add, .i64Add8U, .i64Add16U, .i64Add32U: - initialValue + operand - case .i32Sub, .i32Sub8U, .i32Sub16U, .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U: - initialValue - operand - case .i32And, .i32And8U, .i32And16U, .i64And, .i64And8U, .i64And16U, .i64And32U: - initialValue & operand - case .i32Or, .i32Or8U, .i32Or16U, .i64Or, .i64Or8U, .i64Or16U, .i64Or32U: - initialValue | operand - case .i32Xor, .i32Xor8U, .i32Xor16U, .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U: - initialValue ^ operand - case .i32Xchg, .i32Xchg8U, .i32Xchg16U, .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: - operand - } + let expectedFinal = + switch op { + case .i32Add, .i32Add8U, .i32Add16U, .i64Add, .i64Add8U, .i64Add16U, + .i64Add32U: + initialValue + operand + case .i32Sub, .i32Sub8U, .i32Sub16U, .i64Sub, .i64Sub8U, .i64Sub16U, + .i64Sub32U: + initialValue - operand + case .i32And, .i32And8U, .i32And16U, .i64And, .i64And8U, .i64And16U, + .i64And32U: + initialValue & operand + case .i32Or, .i32Or8U, .i32Or16U, .i64Or, .i64Or8U, .i64Or16U, + .i64Or32U: + initialValue | operand + case .i32Xor, .i32Xor8U, .i32Xor16U, .i64Xor, .i64Xor8U, .i64Xor16U, + .i64Xor32U: + initialValue ^ operand + case .i32Xchg, .i32Xchg8U, .i32Xchg16U, .i64Xchg, .i64Xchg8U, + .i64Xchg16U, .i64Xchg32U: + operand + } expectedResults.append("\(initialValue),\(expectedFinal)\n") } } @@ -282,20 +318,21 @@ class WasmAtomicsTests: XCTestCase { var expectedResults: [String] = [] let js = buildAndLiftProgram { b in - let testCases: [( - op: WasmAtomicCmpxchgType, - storeType: WasmAtomicStoreType, - loadType: WasmAtomicLoadType, - valueType: ILType - )] = [ - (.i32Cmpxchg, .i32Store, .i32Load, .wasmi32), - (.i32Cmpxchg8U, .i32Store8, .i32Load8U, .wasmi32), - (.i32Cmpxchg16U, .i32Store16, .i32Load16U, .wasmi32), - (.i64Cmpxchg, .i64Store, .i64Load, .wasmi64), - (.i64Cmpxchg8U, .i64Store8, .i64Load8U, .wasmi64), - (.i64Cmpxchg16U, .i64Store16, .i64Load16U, .wasmi64), - (.i64Cmpxchg32U, .i64Store32, .i64Load32U, .wasmi64), - ] + let testCases: + [( + op: WasmAtomicCmpxchgType, + storeType: WasmAtomicStoreType, + loadType: WasmAtomicLoadType, + valueType: ILType + )] = [ + (.i32Cmpxchg, .i32Store, .i32Load, .wasmi32), + (.i32Cmpxchg8U, .i32Store8, .i32Load8U, .wasmi32), + (.i32Cmpxchg16U, .i32Store16, .i32Load16U, .wasmi32), + (.i64Cmpxchg, .i64Store, .i64Load, .wasmi64), + (.i64Cmpxchg8U, .i64Store8, .i64Load8U, .wasmi64), + (.i64Cmpxchg16U, .i64Store16, .i64Load16U, .wasmi64), + (.i64Cmpxchg32U, .i64Store32, .i64Load32U, .wasmi64), + ] let initialValue: Int64 = 12 let replacement: Int64 = 10 @@ -308,27 +345,49 @@ class WasmAtomicsTests: XCTestCase { for (op, storeType, loadType, valueType) in testCases { let returnType = valueType // Successful exchange - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) let expected = valueToStore - let replacement = (valueType == .wasmi32) ? f.consti32(Int32(replacement)) : f.consti64(replacement) + let replacement = + (valueType == .wasmi32) + ? f.consti32(Int32(replacement)) : f.consti64(replacement) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicCmpxchg(memory: memory, address: address, expected: expected, replacement: replacement, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicCmpxchg( + memory: memory, address: address, expected: expected, + replacement: replacement, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: loadType, offset: 0) return [originalValue, finalValue] } expectedResults.append("\(initialValue),\(replacement)\n") // Unsuccessful exchange - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) - let expected = (valueType == .wasmi32) ? f.consti32(Int32(initialValue - 1)) : f.consti64(initialValue - 1) - let replacement = (valueType == .wasmi32) ? f.consti32(Int32(replacement)) : f.consti64(replacement) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + let expected = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue - 1)) : f.consti64(initialValue - 1) + let replacement = + (valueType == .wasmi32) + ? f.consti32(Int32(replacement)) : f.consti64(replacement) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicCmpxchg(memory: memory, address: address, expected: expected, replacement: replacement, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicCmpxchg( + memory: memory, address: address, expected: expected, + replacement: replacement, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: loadType, offset: 0) return [originalValue, finalValue] } expectedResults.append("\(initialValue),\(initialValue)\n") @@ -349,4 +408,4 @@ class WasmAtomicsTests: XCTestCase { testForOutput(program: js, runner: runner, outputString: expectedOutput) } -} \ No newline at end of file +} diff --git a/Tests/FuzzilliTests/WasmTableTests.swift b/Tests/FuzzilliTests/WasmTableTests.swift index 2e4f9335f..9234ab415 100644 --- a/Tests/FuzzilliTests/WasmTableTests.swift +++ b/Tests/FuzzilliTests/WasmTableTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class WasmTableTests: XCTestCase { @@ -22,7 +23,8 @@ class WasmTableTests: XCTestCase { let js = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in - let table = wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, maxSize: 20, isTable64: false) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), minSize: 10, maxSize: 20, isTable64: false) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { f, _, _ in let size = f.wasmTableSize(table: table) diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 8fe71c418..5006e0c91 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli @discardableResult @@ -34,28 +35,60 @@ func testForOutput(program: String, runner: JavaScriptExecutor, outputString: St func testForOutputRegex(program: String, runner: JavaScriptExecutor, outputPattern: String) { let result = testExecuteScript(program: program, runner: runner) let matches = result.output.matches(of: try! Regex(outputPattern)) - XCTAssertEqual(matches.isEmpty, false, "Output:\n\(result.output)\nExpected output:\n\(outputPattern)Error Output:\n\(result.error)") + XCTAssertEqual( + matches.isEmpty, false, + "Output:\n\(result.output)\nExpected output:\n\(outputPattern)Error Output:\n\(result.error)" + ) } -func testForErrorOutput(program: String, runner: JavaScriptExecutor, errorMessageContains errormsg: String) { +func testForErrorOutput( + program: String, runner: JavaScriptExecutor, errorMessageContains errormsg: String +) { let result = testExecuteScript(program: program, runner: runner) - XCTAssert(result.output.contains(errormsg) || result.error.contains(errormsg), "Error messages don't match, got stdout:\n\(result.output)\nstderr:\n\(result.error)") + XCTAssert( + result.output.contains(errormsg) || result.error.contains(errormsg), + "Error messages don't match, got stdout:\n\(result.output)\nstderr:\n\(result.error)") } class WasmSignatureConversionTests: XCTestCase { func testJsSignatureConversion() { - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmi32] => [.wasmi32]) - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmf32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmf32] => [.wasmi32]) + XCTAssertEqual( + ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, + availableTypes: WeightedList([ + (.wasmi32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1), + ])), [.wasmi32] => [.wasmi32]) + XCTAssertEqual( + ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, + availableTypes: WeightedList([ + (.wasmf32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1), + ])), [.wasmf32] => [.wasmi32]) } func testWasmSignatureConversion() { - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmi64] => [.wasmf32]), [.integer, .bigint] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmExnRef()] => [.wasmf64]), [.integer, .jsAnything] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmExternRef(), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.Index(), nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.WasmExtern, nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmi64] => [.wasmf32]), + [.integer, .bigint] => .float) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmi32, .wasmExnRef()] => [.wasmf64]), [.integer, .jsAnything] => .float) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmExternRef(), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmRef(.Index(), nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmRef(.WasmExtern, nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) // TODO(cffsmith): Change this once we know how we want to represent .wasmSimd128 types in JS. - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmSimd128] => [.wasmSimd128]), [.jsAnything] => .jsAnything) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature([.wasmSimd128] => [.wasmSimd128]), + [.jsAnything] => .jsAnything) } } @@ -71,12 +104,15 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, arg in let var64 = function.consti64(41) - let added = function.wasmi64BinOp(var64, arg[0], binOpKind: WasmIntegerBinaryOpKind.Add) + let added = function.wasmi64BinOp( + var64, arg[0], binOpKind: WasmIntegerBinaryOpKind.Add) return [added] } - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { function, label, arg in - let subbed = function.wasmi64BinOp(arg[0], arg[1], binOpKind: WasmIntegerBinaryOpKind.Sub) + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { + function, label, arg in + let subbed = function.wasmi64BinOp( + arg[0], arg[1], binOpKind: WasmIntegerBinaryOpKind.Sub) return [subbed] } } @@ -88,7 +124,8 @@ class WasmFoundationTests: XCTestCase { let num = b.loadBigInt(1) let res1 = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [num]) - let res2 = b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: [res1, num]) + let res2 = b.callMethod( + module.getExportedMethod(at: 2), on: exports, withArgs: [res1, num]) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -104,7 +141,8 @@ class WasmFoundationTests: XCTestCase { let runner = try GetJavaScriptExecutorOrSkipTest() let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in function.wasmBranchIf(args[0], to: label, args: args) return [function.consti32(-1)] } @@ -113,7 +151,8 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let res0 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res0)]) } @@ -125,18 +164,27 @@ class WasmFoundationTests: XCTestCase { let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in // Test branch if and fall-through. - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmBranchIf(args[0], to: label, args: [function.consti32(1), function.consti64(2), function.constf32(3)]) + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmBranchIf( + args[0], to: label, + args: [function.consti32(1), function.consti64(2), function.constf32(3)]) return [function.consti32(4), function.consti64(5), function.constf32(6)] } // Test explicit return. - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmReturn([function.consti32(7), function.consti64(8), function.constf32(9)]) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmReturn([ + function.consti32(7), function.consti64(8), function.constf32(9), + ]) return [function.consti32(-1), function.consti64(-1), function.constf32(-1)] } // Test unconditional branch. - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmBranch(to: label, args: [function.consti32(10), function.consti64(11), function.constf32(12)]) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmBranch( + to: label, + args: [function.consti32(10), function.consti64(11), function.constf32(12)]) return [function.consti32(-1), function.consti64(-1), function.constf32(-1)] } } @@ -144,13 +192,16 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") [ - b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]), - b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]), + b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]), + b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]), b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: []), b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: []), - ].forEach {b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: $0)])} + ].forEach { b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: $0)]) } } - testForOutput(program: jsProg, runner: runner, outputString: "1,2,3\n4,5,6\n7,8,9\n10,11,12\n") + testForOutput( + program: jsProg, runner: runner, outputString: "1,2,3\n4,5,6\n7,8,9\n10,11,12\n") } func testExportNaming() throws { @@ -158,14 +209,23 @@ class WasmFoundationTests: XCTestCase { let jsProg = buildAndLiftProgram { b in // This test tests whether re-exported imports and module defined globals are re-ordered from the typer. let wasmGlobali32: Variable = b.createWasmGlobal(value: .wasmi32(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali32), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi32, isMutable: true))) - - let wasmGlobalf32: Variable = b.createWasmGlobal(value: .wasmf32(42.0), isMutable: false) - XCTAssertEqual(b.type(of: wasmGlobalf32), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmf32, isMutable: false))) + XCTAssertEqual( + b.type(of: wasmGlobali32), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi32, isMutable: true))) + + let wasmGlobalf32: Variable = b.createWasmGlobal( + value: .wasmf32(42.0), isMutable: false) + XCTAssertEqual( + b.type(of: wasmGlobalf32), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmf32, isMutable: false))) let module = b.buildWasmModule { wasmModule in // Imports are always before internal globals, this breaks the logic if we add a global and then import a global. - wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in + wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in // This load forces an import // This should be iwg0 fun.wasmLoadGlobal(globalVariable: wasmGlobalf32) @@ -173,7 +233,7 @@ class WasmFoundationTests: XCTestCase { } // This adds an internally defined global, it should be wg0 wasmModule.addGlobal(wasmGlobal: .wasmi64(4141), isMutable: true) - wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in + wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in // This load forces an import // This should be iwg1 fun.wasmLoadGlobal(globalVariable: wasmGlobali32) @@ -183,20 +243,30 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: ["iwg0", "iwg1", "wg0"], withMethods: ["w1", "w0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: ["iwg0", "iwg1", "wg0"], + withMethods: ["w1", "w0"])) let outputFunc = b.createNamedVariable(forBuiltin: "output") // Now let's actually see what the re-exported values are and see that the types don't match with what the programbuilder will see. // TODO: Is this an issue? will the programbuilder still be queriable for variables? I think so, it is internally consistent within the module... let firstExport = b.getProperty("iwg0", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: firstExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: firstExport))]) let secondExport = b.getProperty("wg0", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: secondExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: secondExport))]) let thirdExport = b.getProperty("iwg1", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: thirdExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: thirdExport))]) } testForOutput(program: jsProg, runner: runner, outputString: "42\n4141\n1337\n") @@ -222,28 +292,43 @@ class WasmFoundationTests: XCTestCase { XCTAssertEqual(b.type(of: functionB).signature, [.integer] => .number) let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { + function, label, args in // Manually set the availableTypes here for testing - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([(.wasmi64, 1)])) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, + availableTypes: WeightedList([(.wasmi64, 1)])) XCTAssertEqual(wasmSignature, [.wasmi64] => [.wasmi64]) - let varA = function.wasmJsCall(function: functionA, withArgs: [args[0]], withWasmSignature: wasmSignature)! + let varA = function.wasmJsCall( + function: functionA, withArgs: [args[0]], withWasmSignature: wasmSignature)! return [varA] } wasmModule.addWasmFunction(with: [] => [.wasmf32]) { function, _, _ in // Manually set the availableTypes here for testing - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionB).signature!, availableTypes: WeightedList([(.wasmi32, 1), (.wasmf32, 1)])) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionB).signature!, + availableTypes: WeightedList([(.wasmi32, 1), (.wasmf32, 1)])) XCTAssertEqual(wasmSignature.parameterTypes.count, 1) - XCTAssert(wasmSignature.parameterTypes[0] == .wasmi32 || wasmSignature.parameterTypes[0] == .wasmf32) - XCTAssert(wasmSignature.outputTypes == [.wasmi32] || wasmSignature.outputTypes == [.wasmf32]) - let varA = wasmSignature.parameterTypes[0] == .wasmi32 ? function.consti32(1337) : function.constf32(1337) - let varRet = function.wasmJsCall(function: functionB, withArgs: [varA], withWasmSignature: wasmSignature)! + XCTAssert( + wasmSignature.parameterTypes[0] == .wasmi32 + || wasmSignature.parameterTypes[0] == .wasmf32) + XCTAssert( + wasmSignature.outputTypes == [.wasmi32] + || wasmSignature.outputTypes == [.wasmf32]) + let varA = + wasmSignature.parameterTypes[0] == .wasmi32 + ? function.consti32(1337) : function.constf32(1337) + let varRet = function.wasmJsCall( + function: functionB, withArgs: [varA], withWasmSignature: wasmSignature)! return [varRet] } wasmModule.addWasmFunction(with: [] => [.wasmf32]) { function, _, _ in let varA = function.constf32(1337.1) - let varRet = function.wasmJsCall(function: functionB, withArgs: [varA], withWasmSignature: [.wasmf32] => [.wasmf32])! + let varRet = function.wasmJsCall( + function: functionB, withArgs: [varA], + withWasmSignature: [.wasmf32] => [.wasmf32])! return [varRet] } } @@ -261,7 +346,8 @@ class WasmFoundationTests: XCTestCase { b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res1)]) // We do not control whether the JS function is imported with a floating point or an integer type, so the // fractional digits might be lost. Round the result to make the output predictable. - let res2Rounded = b.callFunction(b.createNamedVariable(forBuiltin: "Math.round"), withArgs: [res2]) + let res2Rounded = b.callFunction( + b.createNamedVariable(forBuiltin: "Math.round"), withArgs: [res2]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res2Rounded)]) } @@ -286,7 +372,8 @@ class WasmFoundationTests: XCTestCase { let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports) let integer = b.loadBigInt(1) - let res1 = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [integer]) + let res1 = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [integer]) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -338,14 +425,22 @@ class WasmFoundationTests: XCTestCase { let tag = wasmModule.addTag(parameterTypes: [.wasmi32, .wasmi32]) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123), function.consti32(456)]) - }, catchClauses: [(tag: tag, body: { _, _, e in - // The exception values are e[0] = 123 and e[1] = 456. - function.wasmReassign(variable: e[0], to: e[1]) - // The exception values should now be e[0] = 456, e[1] = 456. - function.wasmReturn(e[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { _ in + function.WasmBuildThrow( + tag: tag, inputs: [function.consti32(123), function.consti32(456)]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, e in + // The exception values are e[0] = 123 and e[1] = 456. + function.wasmReassign(variable: e[0], to: e[1]) + // The exception values should now be e[0] = 456, e[1] = 456. + function.wasmReturn(e[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -381,12 +476,15 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobali64: Variable = b.createWasmGlobal(value: .wasmi64(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: wasmGlobali64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .wasmi64(1339), isMutable: true) - // Function 0 wasmModule.addWasmFunction(with: [] => []) { function, _, _ in // This forces an import of the wasmGlobali64 @@ -420,9 +518,11 @@ class WasmFoundationTests: XCTestCase { let nameOfExportedGlobals = ["iwg0", "wg0"] let nameOfExportedFunctions = ["w0", "w1", "w2"] - - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: nameOfExportedGlobals, withMethods: nameOfExportedFunctions)) - + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: nameOfExportedGlobals, + withMethods: nameOfExportedFunctions)) let value = b.getProperty("value", of: wasmGlobali64) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -451,7 +551,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in // Note that globals of exnref can only be defined in wasm, not in JS. let global = wasmModule.addGlobal(wasmGlobal: .exnref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmExnRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmExnRef(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let value = function.wasmLoadGlobal(globalVariable: global) @@ -460,8 +564,12 @@ class WasmFoundationTests: XCTestCase { // Throw an exception, catch it and store it in the global. wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [catchLabel], catches: [.AllRef]) { _, _ in + let exnref = function.wasmBuildBlockWithResults( + with: [] => [.wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [catchLabel], catches: [.AllRef] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(42)]) return [] } @@ -473,9 +581,14 @@ class WasmFoundationTests: XCTestCase { // Rethrow the exception stored in the global, catch it and extract the integer. wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.Ref] + ) { _, _ in + function.wasmBuildThrowRef( + exception: function.wasmLoadGlobal(globalVariable: global)) return [] } return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] @@ -509,9 +622,14 @@ class WasmFoundationTests: XCTestCase { let otherModule = b.buildWasmModule { wasmModule in // Rethrow the exception stored in the global, catch it and extract the integer. wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.Ref] + ) { _, _ in + function.wasmBuildThrowRef( + exception: function.wasmLoadGlobal(globalVariable: global)) return [] } return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] @@ -538,7 +656,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .externref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmExternRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmExternRef(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] @@ -579,7 +701,11 @@ class WasmFoundationTests: XCTestCase { // TODO(pawkra): add shared ref variant. let global: Variable = b.createWasmGlobal(value: .externref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(), isMutable: true))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "undefined" (because we didn't provide an explicit initialization). @@ -604,7 +730,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .i31ref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmI31Ref(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmI31Ref(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmI31Ref()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] @@ -644,7 +774,11 @@ class WasmFoundationTests: XCTestCase { // TODO(pawkra): add shared ref variant. let global: Variable = b.createWasmGlobal(value: .i31ref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(), isMutable: true))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "null" (because we didn't provide an explicit initialization). @@ -668,16 +802,25 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let javaScriptTable = b.createWasmTable(elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64) - XCTAssertEqual(b.type(of: javaScriptTable), .wasmTable(wasmTableType: WasmTableType(elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64, knownEntries: []))) + let javaScriptTable = b.createWasmTable( + elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64) + XCTAssertEqual( + b.type(of: javaScriptTable), + .wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), + isTable64: isTable64, knownEntries: []))) let object = b.createObject(with: ["a": b.loadInt(41), "b": b.loadInt(42)]) // Set a value into the table - b.callMethod("set", on: javaScriptTable, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1), object]) + b.callMethod( + "set", on: javaScriptTable, + withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1), object]) let module = b.buildWasmModule { wasmModule in - let tableRef = wasmModule.addTable(elementType: .wasmExternRef(), minSize: 2, isTable64: isTable64) + let tableRef = wasmModule.addTable( + elementType: .wasmExternRef(), minSize: 2, isTable64: isTable64) wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, _, _ in let offset = isTable64 ? function.consti64(0) : function.consti32(0) @@ -696,7 +839,8 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let json = b.createNamedVariable(forBuiltin: "JSON") - b.callFunction(outputFunc, withArgs: [b.callMethod("stringify", on: json, withArgs: [res0])]) + b.callFunction( + outputFunc, withArgs: [b.callMethod("stringify", on: json, withArgs: [res0])]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -726,36 +870,49 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, params in [function.wasmi32BinOp(params[0], function.consti32(1), binOpKind: .Add)] } - wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), .init(indexInTable: 1, signature: [] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: isTable64) + wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), + .init(indexInTable: 1, signature: [] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: isTable64) } let exports = module.loadExports() let table = b.getProperty("wt0", of: exports) - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: ["wt0"], withMethods: ["w0", "iw0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: ["wt0"], withMethods: ["w0", "iw0"])) let importedFunction = b.getProperty("iw0", of: exports) XCTAssertEqual(b.type(of: importedFunction), .function([] => .bigint)) // This is the table type that we expect to see on the exports based on the dynamic object group typing. - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: isTable64, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), - .init(indexInTable: 1, signature: [] => [.wasmi64]) - - ])) + let tableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: isTable64, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), + .init(indexInTable: 1, signature: [] => [.wasmi64]), + + ])) XCTAssertEqual(b.type(of: table), tableType) - let tableElement0 = b.callMethod("get", on: table, withArgs: [isTable64 ? b.loadBigInt(0) : b.loadInt(0)]) - let tableElement1 = b.callMethod("get", on: table, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1)]) + let tableElement0 = b.callMethod( + "get", on: table, withArgs: [isTable64 ? b.loadBigInt(0) : b.loadInt(0)]) + let tableElement1 = b.callMethod( + "get", on: table, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1)]) let output0 = b.callFunction(tableElement0, withArgs: [b.loadInt(42)]) let output1 = b.callFunction(tableElement1, withArgs: []) @@ -792,20 +949,31 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: false) - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - let results = fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: false) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + let results = fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.wasmi64BinOp(results[0], results[1], binOpKind: .Add)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) } } @@ -842,37 +1010,53 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - wasmModule.addTable(elementType: .wasmFuncRef(), + wasmModule.addTable( + elementType: .wasmFuncRef(), minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], definedEntryValues: [wasmFunction, jsFunction], isTable64: false) } let table = b.getProperty("wt0", of: module.loadExports()) - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), - .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]) - ])) + let tableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ])) XCTAssertEqual(b.type(of: table), tableType) let module2 = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - let results = fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + let results = fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.wasmi64BinOp(results[0], results[1], binOpKind: .Add)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) } - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmFuncRef()]) { function, label, params in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmFuncRef()]) { + function, label, params in [function.wasmTableGet(tableRef: table, idx: params[0])] } - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { + function, label, params in [params[0], params[0]] } } @@ -883,14 +1067,16 @@ class WasmFoundationTests: XCTestCase { let reexportedTable = b.getProperty("iwt0", of: exports) // This is the table type that we expect to see on the exports based on the dynamic object group typing. - let reexportedTableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), - .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]) - - ])) + let reexportedTableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + + ])) XCTAssertEqual(b.type(of: reexportedTable), reexportedTableType) - let callIndirectSig0 = b.getProperty(module2.getExportedMethod(at: 0), of: exports) let result0 = b.callFunction(callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(10)]) let callIndirectSig1 = b.getProperty(module2.getExportedMethod(at: 1), of: exports) @@ -906,8 +1092,11 @@ class WasmFoundationTests: XCTestCase { // It is also possible to change the slot and perform the call_indirect now pointing to a // different function as long as signatures still match. - b.callMethod("set", on: table, withArgs: [b.loadInt(0), b.getProperty(module2.getExportedMethod(at: 3), of: exports)]) - let resultNew = b.callFunction(callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(42)]) + b.callMethod( + "set", on: table, + withArgs: [b.loadInt(0), b.getProperty(module2.getExportedMethod(at: 3), of: exports)]) + let resultNew = b.callFunction( + callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: resultNew)]) let prog = b.finalize() @@ -925,17 +1114,23 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, params in + let callee = wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, params in return [function.wasmi32BinOp(params[0], params[1], binOpKind: .Sub)] } - let calleeMultiResult = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in + let calleeMultiResult = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in return [function.consti32(100), function.consti32(200)] } wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in - let callResult = function.wasmCallDirect(signature: [.wasmi32, .wasmi32] => [.wasmi32], function: callee, functionArgs: [params[0], function.consti32(1)]) - let multiResult = function.wasmCallDirect(signature: [] => [.wasmi32, .wasmi32], function: calleeMultiResult, functionArgs: []) + let callResult = function.wasmCallDirect( + signature: [.wasmi32, .wasmi32] => [.wasmi32], function: callee, + functionArgs: [params[0], function.consti32(1)]) + let multiResult = function.wasmCallDirect( + signature: [] => [.wasmi32, .wasmi32], function: calleeMultiResult, + functionArgs: []) let sum1 = function.wasmi32BinOp(multiResult[0], multiResult[1], binOpKind: .Add) return [function.wasmi32BinOp(sum1, callResult[0], binOpKind: .Add)] } @@ -964,12 +1159,15 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in + let callee = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in return [function.consti32(100), function.consti32(200)] } - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in - function.wasmReturnCallDirect(signature: [] => [.wasmi32, .wasmi32], function: callee, functionArgs: []) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in + function.wasmReturnCallDirect( + signature: [] => [.wasmi32, .wasmi32], function: callee, functionArgs: []) return [function.consti32(-1), function.consti32(-1)] } } @@ -996,20 +1194,31 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: false) - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi64]) { fn, label, params in - fn.wasmReturnCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: false) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi64]) { + fn, label, params in + fn.wasmReturnCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.consti64(-1), fn.consti64(-1)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmReturnCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmReturnCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) return [fn.consti64(-1)] } } @@ -1044,31 +1253,43 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() - let wasmMemory: Variable = b.createWasmMemory(minPages: 10, maxPages: 20, isShared: isShared, isMemory64: isMemory64) - XCTAssertEqual(b.type(of: wasmMemory), .wasmMemory(limits: Limits(min: 10, max: 20), isShared: isShared, isMemory64: isMemory64)) + let wasmMemory: Variable = b.createWasmMemory( + minPages: 10, maxPages: 20, isShared: isShared, isMemory64: isMemory64) + XCTAssertEqual( + b.type(of: wasmMemory), + .wasmMemory( + limits: Limits(min: 10, max: 20), isShared: isShared, isMemory64: isMemory64)) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in let value = function.consti32(1337) let offset = isMemory64 ? function.consti64(10) : function.consti32(10) - function.wasmMemoryStore(memory: wasmMemory, dynamicOffset: offset, value: value, storeType: .I32StoreMem, staticOffset: 0) - let val = function.wasmMemoryLoad(memory: wasmMemory, dynamicOffset: offset, loadType: .I64LoadMem, staticOffset: 0) + function.wasmMemoryStore( + memory: wasmMemory, dynamicOffset: offset, value: value, + storeType: .I32StoreMem, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: wasmMemory, dynamicOffset: offset, loadType: .I64LoadMem, + staticOffset: 0) return [val] } } let viewBuiltin = b.createNamedVariable(forBuiltin: "DataView") - XCTAssertEqual(b.type(of: b.getProperty("buffer", of: wasmMemory)), .jsArrayBuffer | .jsSharedArrayBuffer) + XCTAssertEqual( + b.type(of: b.getProperty("buffer", of: wasmMemory)), + .jsArrayBuffer | .jsSharedArrayBuffer) let view = b.construct(viewBuiltin, withArgs: [b.getProperty("buffer", of: wasmMemory)]) // Read the value of the memory. - let value = b.callMethod("getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) + let value = b.callMethod( + "getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) let exports = module.loadExports() let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports) - let valueAfter = b.callMethod("getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) + let valueAfter = b.callMethod( + "getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res0)]) @@ -1102,21 +1323,28 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let memory = wasmModule.addMemory(minPages: 5, maxPages: 12, isShared: isShared, isMemory64: isMemory64) + let memory = wasmModule.addMemory( + minPages: 5, maxPages: 12, isShared: isShared, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let value = function.consti64(1337) let storeOffset = function.memoryArgument(8, memoryTypeInfo) - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: .I64StoreMem, staticOffset: 2) + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: .I64StoreMem, staticOffset: 2) let loadOffset = function.memoryArgument(10, memoryTypeInfo) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, + staticOffset: 0) return [val] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) testForOutput(program: jsProg, runner: runner, outputString: "1337\n") @@ -1135,7 +1363,7 @@ class WasmFoundationTests: XCTestCase { func simpleDataSegmentInit(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 5, maxPages: 12, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1144,14 +1372,22 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(16), dataSegmentOffset: i32(3), nrOfBytesToUpdate: i32(8)) - return [f.wasmMemoryLoad(memory: memory, dynamicOffset: memIdx(16), loadType: .I64LoadMem, staticOffset: 0)] + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(16), + dataSegmentOffset: i32(3), nrOfBytesToUpdate: i32(8)) + return [ + f.wasmMemoryLoad( + memory: memory, dynamicOffset: memIdx(16), loadType: .I64LoadMem, + staticOffset: 0) + ] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) } // "AAAABBBB" -> 0x4242424241414141 @@ -1169,7 +1405,7 @@ class WasmFoundationTests: XCTestCase { func testDropDataSegment() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in let segment = wasmModule.addDataSegment(segment: [0xAA]) @@ -1185,7 +1421,7 @@ class WasmFoundationTests: XCTestCase { func testDropDataSegmentTwoTimes() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in let segment = wasmModule.addDataSegment(segment: [0xAA]) @@ -1203,7 +1439,7 @@ class WasmFoundationTests: XCTestCase { func testInitSingleMemoryFromTwoSegments(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1213,14 +1449,24 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment1, memory: memory, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) - f.wasmMemoryInit(dataSegment: segment2, memory: memory, memoryOffset: memIdx(4), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) - return [f.wasmMemoryLoad(memory: memory, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0)] + f.wasmMemoryInit( + dataSegment: segment1, memory: memory, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) + f.wasmMemoryInit( + dataSegment: segment2, memory: memory, memoryOffset: memIdx(4), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) + return [ + f.wasmMemoryLoad( + memory: memory, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) + ] } } let res = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } // "AAAABBBB" -> 0x4242424241414141 @@ -1238,7 +1484,7 @@ class WasmFoundationTests: XCTestCase { func testInitTwoMemoriesFromOneSegment(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory1 = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory1).wasmMemoryType! @@ -1248,20 +1494,32 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory1, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) - f.wasmMemoryInit(dataSegment: segment, memory: memory2, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) - let val1 = f.wasmMemoryLoad(memory: memory1, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0) - let val2 = f.wasmMemoryLoad(memory: memory2, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0) + f.wasmMemoryInit( + dataSegment: segment, memory: memory1, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory2, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) + let val1 = f.wasmMemoryLoad( + memory: memory1, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) + let val2 = f.wasmMemoryLoad( + memory: memory2, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) return [val1, val2] } } let res = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } // "AAAABBBB" -> 0x4242424241414141 - testForOutput(program: jsProg, runner: runner, outputString: "4774451407296217409,4774451407296217409\n") + testForOutput( + program: jsProg, runner: runner, + outputString: "4774451407296217409,4774451407296217409\n") } func testInitTwoMemoriesFromOneSegment32() throws { @@ -1275,7 +1533,7 @@ class WasmFoundationTests: XCTestCase { func testMemoryInitOutOfBoundsMemory(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1285,14 +1543,18 @@ class WasmFoundationTests: XCTestCase { // Memory size is one page (65536 bytes), so this should be out of bounds. let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(65536), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(1)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(65536), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(1)) return [] } } b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) } - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } func testMemoryInitOutOfBoundsMemory32() throws { @@ -1306,7 +1568,7 @@ class WasmFoundationTests: XCTestCase { func testMemoryInitOutOfBoundsSegment(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1316,14 +1578,18 @@ class WasmFoundationTests: XCTestCase { // Data segment size is 1, so this should be out of bounds. let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(2)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(2)) return [] } } b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) } - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } func testMemoryInitOutOfBoundsSegment32() throws { @@ -1334,7 +1600,7 @@ class WasmFoundationTests: XCTestCase { try testMemoryInitOutOfBoundsSegment(isMemory64: true) } - func testMemory64Index() throws{ + func testMemory64Index() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -1349,16 +1615,22 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => []) { function, _, _ in let value = function.consti64(1337) let storeOffset = function.consti64(1 << 32) - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: .I64StoreMem, staticOffset: 2) + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: .I64StoreMem, staticOffset: 2) return [] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } // This test doesn't check the result of the Wasm loads, just exectues them. @@ -1379,7 +1651,9 @@ class WasmFoundationTests: XCTestCase { for loadType in WasmMemoryLoadType.allCases { wasmModule.addWasmFunction(with: [] => [loadType.numberType()]) { function, _, _ in let loadOffset = isMemory64 ? function.consti64(9) : function.consti32(9) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: loadType, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: loadType, + staticOffset: 0) return [val] } } @@ -1387,7 +1661,9 @@ class WasmFoundationTests: XCTestCase { for idx in 0.. []) { function, _, _ in let storeOffset = isMemory64 ? function.consti64(13) : function.consti32(13) - let value = switch storeType.numberType() { + let value = + switch storeType.numberType() { case .wasmi32: function.consti32(8) case .wasmi64: function.consti64(8) case .wasmf32: function.constf32(8.4) case .wasmf64: function.constf64(8.4) case .wasmSimd128: function.constSimd128(value: Array(0..<16)) default: fatalError("Non-existent value to be stored") - } - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: storeType, staticOffset: 2) + } + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: storeType, staticOffset: 2) return [] } } @@ -1434,7 +1713,9 @@ class WasmFoundationTests: XCTestCase { for idx in 0.. [.wasmi32]) { function, _, _ in - let offset = isMemory64 ? function.consti64(Int64(42)) : function.consti32(Int32(42)) - function.wasmMemoryStore(memory: memory0, dynamicOffset: offset, value: function.constf32(1.0), storeType: .F32StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory1, dynamicOffset: offset, value: function.constf64(2.0), storeType: .F64StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory2, dynamicOffset: offset, value: function.consti32(3), storeType: .I32StoreMem, staticOffset: 0) - let load0 = function.wasmMemoryLoad(memory: memory0, dynamicOffset: offset, loadType: .F32LoadMem, staticOffset: 0) - let load1 = function.wasmMemoryLoad(memory: memory1, dynamicOffset: offset, loadType: .F64LoadMem, staticOffset: 0) - let load2 = function.wasmMemoryLoad(memory: memory2, dynamicOffset: offset, loadType: .I32LoadMem, staticOffset: 0) + let offset = + isMemory64 ? function.consti64(Int64(42)) : function.consti32(Int32(42)) + function.wasmMemoryStore( + memory: memory0, dynamicOffset: offset, value: function.constf32(1.0), + storeType: .F32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory1, dynamicOffset: offset, value: function.constf64(2.0), + storeType: .F64StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory2, dynamicOffset: offset, value: function.consti32(3), + storeType: .I32StoreMem, staticOffset: 0) + let load0 = function.wasmMemoryLoad( + memory: memory0, dynamicOffset: offset, loadType: .F32LoadMem, staticOffset: 0) + let load1 = function.wasmMemoryLoad( + memory: memory1, dynamicOffset: offset, loadType: .F64LoadMem, staticOffset: 0) + let load2 = function.wasmMemoryLoad( + memory: memory2, dynamicOffset: offset, loadType: .I32LoadMem, staticOffset: 0) let trunc0 = function.truncatef32Toi32(load0, isSigned: true) let trunc1 = function.truncatef64Toi32(load1, isSigned: true) @@ -1484,7 +1778,9 @@ class WasmFoundationTests: XCTestCase { } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -1505,14 +1801,16 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let memoryA = b.createWasmMemory(minPages: 7, maxPages: 7, isShared: false, isMemory64: isMemory64) + let memoryA = b.createWasmMemory( + minPages: 7, maxPages: 7, isShared: false, isMemory64: isMemory64) let module = b.buildWasmModule { wasmModule in let memoryB = wasmModule.addMemory(minPages: 5, maxPages: 12, isMemory64: isMemory64) let memoryC = wasmModule.addMemory(minPages: 0, maxPages: 1, isMemory64: isMemory64) [memoryA, memoryB, memoryC].forEach { memory in let addrType: ILType = isMemory64 ? .wasmi64 : .wasmi32 - wasmModule.addWasmFunction(with: [] => [addrType, addrType, addrType]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [addrType, addrType, addrType]) { + function, label, args in let growBy = isMemory64 ? function.consti64(1) : function.consti32(1) return [ function.wasmMemorySize(memory: memory), @@ -1525,7 +1823,9 @@ class WasmFoundationTests: XCTestCase { (0..<3).forEach { let res = b.callMethod(module.getExportedMethod(at: $0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } let jsProg = fuzzer.lifter.lift(b.finalize()) @@ -1559,18 +1859,24 @@ class WasmFoundationTests: XCTestCase { let fillOffset = function.memoryArgument(100, memoryTypeInfo) let byteToSet = function.consti32(0xAA) let nrOfBytesToUpdate = function.memoryArgument(4, memoryTypeInfo) - function.wasmMemoryFill(memory: memory, offset: fillOffset, byteToSet: byteToSet, nrOfBytesToUpdate: nrOfBytesToUpdate) - let loadOffset = function.memoryArgument(102, memoryTypeInfo) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, staticOffset: 0) + function.wasmMemoryFill( + memory: memory, offset: fillOffset, byteToSet: byteToSet, + nrOfBytesToUpdate: nrOfBytesToUpdate) + let loadOffset = function.memoryArgument(102, memoryTypeInfo) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, + staticOffset: 0) return [val] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) - testForOutput(program: jsProg, runner: runner, outputString: "43690\n") // 0x 00 00 AA AA + testForOutput(program: jsProg, runner: runner, outputString: "43690\n") // 0x 00 00 AA AA } func testMemoryBulkOperations32() throws { @@ -1584,17 +1890,20 @@ class WasmFoundationTests: XCTestCase { func memoryCopy(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let mem1 = wasmModule.addMemory(minPages: 1, maxPages: 2, isMemory64: isMemory64) let mem2 = wasmModule.addMemory(minPages: 1, maxPages: 2, isMemory64: isMemory64) let memTypeInfo = b.type(of: mem1).wasmMemoryType! - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { function, _, _ in - let setValueAtOffset = { (value: Int32, offsetValue: Int64) -> () in + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { + function, _, _ in + let setValueAtOffset = { (value: Int32, offsetValue: Int64) -> Void in let valToSet = function.consti32(value) let offset = function.memoryArgument(offsetValue, memTypeInfo) - function.wasmMemoryStore(memory: mem1, dynamicOffset: offset, value: valToSet, storeType: .I32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: mem1, dynamicOffset: offset, value: valToSet, + storeType: .I32StoreMem, staticOffset: 0) } setValueAtOffset(111, 4) setValueAtOffset(222, 8) @@ -1603,18 +1912,24 @@ class WasmFoundationTests: XCTestCase { let dstOffset = function.memoryArgument(128, memTypeInfo) let srcOffset = function.memoryArgument(8, memTypeInfo) let size = function.memoryArgument(4, memTypeInfo) - function.wasmMemoryCopy(dstMemory: mem2, srcMemory: mem1, dstOffset: dstOffset, srcOffset: srcOffset, size: size) + function.wasmMemoryCopy( + dstMemory: mem2, srcMemory: mem1, dstOffset: dstOffset, + srcOffset: srcOffset, size: size) let loadAtOffset = { (offsetValue: Int64) -> Variable in let dynamicOffset = function.memoryArgument(offsetValue, memTypeInfo) - return function.wasmMemoryLoad(memory: mem2, dynamicOffset: dynamicOffset, loadType: .I32LoadMem, staticOffset: 0) + return function.wasmMemoryLoad( + memory: mem2, dynamicOffset: dynamicOffset, loadType: .I32LoadMem, + staticOffset: 0) } return [loadAtOffset(124), loadAtOffset(128), loadAtOffset(132)] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) } testForOutput(program: jsProg, runner: runner, outputString: "0,222,0\n") @@ -1636,259 +1951,395 @@ class WasmFoundationTests: XCTestCase { let testCases: [((ProgramBuilder.WasmModule, Variable) -> Void, String)] = [ // Test v128.load. - ({wasmModule, memory in - wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(3), storeType: .I64StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(8), - value: function.consti64(6), storeType: .I64StoreMem, staticOffset: 0) - - let val = function.wasmSimdLoad(kind: .LoadS128, memory: memory, - dynamicOffset: const(0), staticOffset: 0) - let sum = function.wasmi64BinOp( - function.wasmSimdExtractLane(kind: .I64x2, val, 0), - function.wasmSimdExtractLane(kind: .I64x2, val, 1), binOpKind: .Add) - return [sum] - } - }, "9"), + ( + { wasmModule, memory in + wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(3), storeType: .I64StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(8), + value: function.consti64(6), storeType: .I64StoreMem, staticOffset: 0) + + let val = function.wasmSimdLoad( + kind: .LoadS128, memory: memory, + dynamicOffset: const(0), staticOffset: 0) + let sum = function.wasmi64BinOp( + function.wasmSimdExtractLane(kind: .I64x2, val, 0), + function.wasmSimdExtractLane(kind: .I64x2, val, 1), binOpKind: .Add) + return [sum] + } + }, "9" + ), // Test v128.store. - ({wasmModule, memory in - wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I64x2, function.consti64(21)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 0) - let loadValue1 = function.wasmMemoryLoad(memory: memory, - dynamicOffset: const(0), loadType: .I64LoadMem, staticOffset: 0) - let loadValue2 = function.wasmMemoryLoad(memory: memory, - dynamicOffset: const(8), loadType: .I64LoadMem, staticOffset: 0) - return [function.wasmi64BinOp(loadValue1, loadValue2, binOpKind: .Add)] - } - }, "42"), + ( + { wasmModule, memory in + wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I64x2, function.consti64(21)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 0) + let loadValue1 = function.wasmMemoryLoad( + memory: memory, + dynamicOffset: const(0), loadType: .I64LoadMem, staticOffset: 0) + let loadValue2 = function.wasmMemoryLoad( + memory: memory, + dynamicOffset: const(8), loadType: .I64LoadMem, staticOffset: 0) + return [function.wasmi64BinOp(loadValue1, loadValue2, binOpKind: .Add)] + } + }, "42" + ), // Test v128.load8x8_s. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(-1)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load8x8S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0)} - } - }, "-1,-1,-1,-1,-1,-1,-1,-1"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(-1)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load8x8S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0) + } + } + }, "-1,-1,-1,-1,-1,-1,-1,-1" + ), // Test v128.load8x8_u. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(255)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load8x8U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8U, loaded, $0)} - } - }, "255,255,255,255,255,255,255,255"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I8x16, function.consti32(255)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load8x8U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8U, loaded, $0) + } + } + }, "255,255,255,255,255,255,255,255" + ), // Test v128.load16x4_s. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(-2)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load16x4S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "-2,-2,-2,-2"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(-2)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load16x4S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "-2,-2,-2,-2" + ), // Test v128.load16x4_u. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(65432)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load16x4U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "65432,65432,65432,65432"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I16x8, function.consti32(65432)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load16x4U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "65432,65432,65432,65432" + ), // Test v128.load32x2_s. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I32x4, function.consti32(-3)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load32x2S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "-3,-3"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I32x4, function.consti32(-3)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load32x2S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "-3,-3" + ), // Test v128.load32x2_u. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat( - kind: .I32x4, function.consti32(-171510507)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load32x2U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "4123456789,4123456789"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I32x4, function.consti32(-171_510_507)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load32x2U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "4123456789,4123456789" + ), // Test v128.load8_splat. - ({wasmModule, memory in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(7), storeType: .I32StoreMem8, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load8Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<16).map {function.wasmSimdExtractLane(kind: .I8x16S, loaded, $0)} - } - }, "7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7"), + ( + { wasmModule, memory in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(7), storeType: .I32StoreMem8, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load8Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<16).map { + function.wasmSimdExtractLane(kind: .I8x16S, loaded, $0) + } + } + }, "7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7" + ), // Test v128.load16_splat. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(8), storeType: .I32StoreMem16, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load16Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0)} - } - }, "8,8,8,8,8,8,8,8"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(8), storeType: .I32StoreMem16, staticOffset: 32 + ) + let loaded = function.wasmSimdLoad( + kind: .Load16Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0) + } + } + }, "8,8,8,8,8,8,8,8" + ), // Test v128.load32_splat. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(9), storeType: .I32StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load32Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "9,9,9,9"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(9), storeType: .I32StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load32Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "9,9,9,9" + ), // Test v128.load64_splat. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(10), storeType: .I64StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load64Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "10,10"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(10), storeType: .I64StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load64Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "10,10" + ), // Test v128.load32_zero. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(11), storeType: .I32StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load32Zero, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "11,0,0,0"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(11), storeType: .I32StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load32Zero, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "11,0,0,0" + ), // Test v128.load64_zero. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(12), storeType: .I64StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load64Zero, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "12,0"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(12), storeType: .I64StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load64Zero, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "12,0" + ), // Test v128.load8_lane and v128.store8_lane. - ({wasmModule, memory in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(13), storeType: .I32StoreMem8, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I8x16, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 15) - function.wasmSimdStoreLane(kind: .Store8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 15) - let reloaded = function.wasmSimdLoadLane(kind: .Load8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<16).map {function.wasmSimdExtractLane(kind: .I8x16U, reloaded, $0)} - } - }, "42,13,42,42,42,42,42,42,42,42,42,42,42,42,42,13"), + ( + { wasmModule, memory in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(13), storeType: .I32StoreMem8, staticOffset: 64 + ) + let splat = function.wasmSimdSplat(kind: .I8x16, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 15) + function.wasmSimdStoreLane( + kind: .Store8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 15) + let reloaded = function.wasmSimdLoadLane( + kind: .Load8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<16).map { + function.wasmSimdExtractLane(kind: .I8x16U, reloaded, $0) + } + } + }, "42,13,42,42,42,42,42,42,42,42,42,42,42,42,42,13" + ), // Test v128.load16_lane and v128.store16_lane. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(14), storeType: .I32StoreMem16, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I16x8, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 7) - function.wasmSimdStoreLane(kind: .Store16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 7) - let reloaded = function.wasmSimdLoadLane(kind: .Load16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8U, reloaded, $0)} - } - }, "42,14,42,42,42,42,42,14"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(14), storeType: .I32StoreMem16, + staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I16x8, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 7) + function.wasmSimdStoreLane( + kind: .Store16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 7) + let reloaded = function.wasmSimdLoadLane( + kind: .Load16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8U, reloaded, $0) + } + } + }, "42,14,42,42,42,42,42,14" + ), // Test v128.load32_lane and v128.store32_lane. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(15), storeType: .I32StoreMem, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I32x4, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 3) - function.wasmSimdStoreLane(kind: .Store32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 3) - let reloaded = function.wasmSimdLoadLane(kind: .Load32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, reloaded, $0)} - } - }, "42,15,42,15"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(15), storeType: .I32StoreMem, staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I32x4, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 3) + function.wasmSimdStoreLane( + kind: .Store32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 3) + let reloaded = function.wasmSimdLoadLane( + kind: .Load32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, reloaded, $0) + } + } + }, "42,15,42,15" + ), // Test v128.load64_lane and v128.store64_lane. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(16), storeType: .I64StoreMem, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I64x2, function.consti64(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 1) - function.wasmSimdStoreLane(kind: .Store64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 1) - let reloaded = function.wasmSimdLoadLane(kind: .Load64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 0) - return [ - function.wasmSimdExtractLane(kind: .I64x2, loaded, 0), - function.wasmSimdExtractLane(kind: .I64x2, loaded, 1), - function.wasmSimdExtractLane(kind: .I64x2, reloaded, 0), - function.wasmSimdExtractLane(kind: .I64x2, reloaded, 1)] - } - }, "42,16,16,16"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(16), storeType: .I64StoreMem, staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I64x2, function.consti64(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 1) + function.wasmSimdStoreLane( + kind: .Store64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 1) + let reloaded = function.wasmSimdLoadLane( + kind: .Load64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 0) + return [ + function.wasmSimdExtractLane(kind: .I64x2, loaded, 0), + function.wasmSimdExtractLane(kind: .I64x2, loaded, 1), + function.wasmSimdExtractLane(kind: .I64x2, reloaded, 0), + function.wasmSimdExtractLane(kind: .I64x2, reloaded, 1), + ] + } + }, "42,16,16,16" + ), ] let module = b.buildWasmModule { wasmModule in @@ -1900,12 +2351,13 @@ class WasmFoundationTests: XCTestCase { for (i, _) in testCases.enumerated() { let res = b.callMethod(module.getExportedMethod(at: i), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) } let jsProg = fuzzer.lifter.lift(b.finalize()) - let expected = testCases.map {$0.1}.joined(separator: "\n") + "\n" + let expected = testCases.map { $0.1 }.joined(separator: "\n") + "\n" testForOutput(program: jsProg, runner: runner, outputString: expected) } @@ -1917,9 +2369,11 @@ class WasmFoundationTests: XCTestCase { try wasmSimdLoadStore(isMemory64: true) } - func wasmSimdSplatAndExtractLane(splat: WasmSimdSplat.Kind, - extractLane: WasmSimdExtractLane.Kind, - replaceLane: WasmSimdReplaceLane.Kind) throws { + func wasmSimdSplatAndExtractLane( + splat: WasmSimdSplat.Kind, + extractLane: WasmSimdExtractLane.Kind, + replaceLane: WasmSimdReplaceLane.Kind + ) throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) @@ -1929,13 +2383,16 @@ class WasmFoundationTests: XCTestCase { XCTAssertEqual(extractLane.laneCount(), replaceLane.laneCount()) let module = b.buildWasmModule { wasmModule in - let sig = [splat.laneType()] => (0.. (0.. [UInt8] = { uint16Array in - return uint16Array.flatMap { value -> [UInt8] in + return uint16Array.flatMap { value -> [UInt8] in let highByte = UInt8((value >> 8) & 0xFF) let lowByte = UInt8(value & 0xFF) return [lowByte, highByte] @@ -2013,618 +2494,1188 @@ class WasmFoundationTests: XCTestCase { return byteArray } - let testCases: [((ProgramBuilder.WasmModule) -> Void, String)] = [ // Test q15mulr_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([16383, 16384, 32767, 65535, 65535, 32765, UInt16(bitPattern: -32768), 32768])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.q15mulr_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8192,8192,32766,0,1,1,32767,-1"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 16383, 16384, 32767, 65535, 65535, 32765, + UInt16(bitPattern: -32768), 32768, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.q15mulr_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8192,8192,32766,0,1,1,32767,-1" + ), // // Test narrow_s - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 128, 256, 0, 1, 128, 256])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([-1, -128, -129, -256, -1, -128, -129, -256].map( {UInt16(bitPattern: $0)}))) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_s) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16S, result, $0)} - } - }, "0,1,127,127,0,1,127,127,-1,-128,-128,-128,-1,-128,-128,-128"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 128, 256, 0, 1, 128, 256])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [-1, -128, -129, -256, -1, -128, -129, -256].map({ + UInt16(bitPattern: $0) + }))) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_s + ) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16S, result, $0) + } + } + }, "0,1,127,127,0,1,127,127,-1,-128,-128,-128,-1,-128,-128,-128" + ), // Test narrow_u - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_u) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} - } - }, "0,1,127,128,255,255,255,255,0,1,127,128,255,255,255,255"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_u + ) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } + } + }, "0,1,127,128,255,255,255,255,0,1,127,128,255,255,255,255" + ), // Test shl - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, 16, 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shl) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,2,4,8,16,18,32,36"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, 16, 18])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shl) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,2,4,8,16,18,32,36" + ), // Test shr_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,1,2,4,4,-8,9"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18, + ])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,1,2,4,4,-8,9" + ), // Test shr_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,1,2,4,4,32760,9"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18, + ])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,1,2,4,4,32760,9" + ), // Test add - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 32767])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8,10,12,14,16,18,20,-32762"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 32767])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8,10,12,14,16,18,20,-32762" + ), // Test add_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray( - [UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32768), UInt16(bitPattern: -32768), 32767, 32767, 32767, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray( - [UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -1), 1, 1, UInt16(bitPattern: -1), UInt16(bitPattern: -2), 4])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-32768,32767,-32768,-32767,32767,32766,32765,11"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray( + [ + UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32768), + UInt16(bitPattern: -32768), 32767, 32767, 32767, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [ + UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -1), 1, 1, + UInt16(bitPattern: -1), UInt16(bitPattern: -2), 4, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.add_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-32768,32767,-32768,-32767,32767,32766,32765,11" + ), // Test add_sat_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray( - [65534, 65534, 65534, 8, 9, 10, 11, 12])) - let varB = function.constSimd128(value: uint16ArrayToByteArray( - [0, 1, 2, 3, 4, 5, 6, 7])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add_sat_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "65534,65535,65535,11,13,15,17,19"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray( + [65534, 65534, 65534, 8, 9, 10, 11, 12])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [0, 1, 2, 3, 4, 5, 6, 7])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.add_sat_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "65534,65535,65535,11,13,15,17,19" + ), // Test sub - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([UInt16(bitPattern:-2), 3, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([32767, 0, 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "32767,3,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + UInt16(bitPattern: -2), 3, 6, 9, 12, 15, 18, 21, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([32767, 0, 1, 2, 3, 4, 5, 6])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "32767,3,5,7,9,11,13,15" + ), // Test sub_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([UInt16(bitPattern:-2), 32000, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([32767, UInt16(bitPattern:-1000), 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-32768,32767,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + UInt16(bitPattern: -2), 32000, 6, 9, 12, 15, 18, 21, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 32767, UInt16(bitPattern: -1000), 1, 2, 3, 4, 5, 6, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.sub_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-32768,32767,5,7,9,11,13,15" + ), // Test sub_sat_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 3, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([1, 0, 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub_sat_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,3,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 3, 6, 9, 12, 15, 18, 21])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([1, 0, 1, 2, 3, 4, 5, 6])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.sub_sat_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,3,5,7,9,11,13,15" + ), // Test mul - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 15])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.mul) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,9,20,33,48,65,84,105"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 15])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.mul) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,9,20,33,48,65,84,105" + ), // Test min_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,1,2,3,4,5,6,65534"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,1,2,3,4,5,6,65534" + ), // Test min_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 8, 0, UInt16(bitPattern:-8), 4, UInt16(bitPattern:-5), 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 0, UInt16(bitPattern:-8), 0, 0, UInt16(bitPattern:-12), 13, 14])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,-8,-8,0,-12,6,7"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 8, 0, UInt16(bitPattern: -8), 4, UInt16(bitPattern: -5), 6, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, 0, UInt16(bitPattern: -8), 0, 0, UInt16(bitPattern: -12), 13, 14, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,-8,-8,0,-12,6,7" + ), // Test max_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "8,9,10,11,12,13,14,65535"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "8,9,10,11,12,13,14,65535" + ), // Test max_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 8, 0, UInt16(bitPattern:-8), 4, UInt16(bitPattern:-5), 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 0, UInt16(bitPattern:-8), 0, 0, UInt16(bitPattern:-12), 13, 14])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8,8,0,0,4,-5,13,14"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 8, 0, UInt16(bitPattern: -8), 4, UInt16(bitPattern: -5), 6, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, 0, UInt16(bitPattern: -8), 0, 0, UInt16(bitPattern: -12), 13, 14, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8,8,0,0,4,-5,13,14" + ), // Test dot_i16x8_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 4, 5, UInt16(bitPattern: -4), 5, 32767, 32767])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([2, 3, 6, 7, 6, UInt16(bitPattern: -7), 32767, 32767])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.dot_i16x8_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,59,-59,2147352578"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 4, 5, UInt16(bitPattern: -4), 5, 32767, 32767, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 2, 3, 6, 7, 6, UInt16(bitPattern: -7), 32767, 32767, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.dot_i16x8_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,59,-59,2147352578" + ), // Test avgr_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 10, 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.avgr_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "4,6,7,9,10,12,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 10, 12, 14, 16, 18, 20, 22])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.avgr_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "4,6,7,9,10,12,13,15" + ), // Test extmul_low_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern:-7)])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_low_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "0,-10,24,42"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern: -7), + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_low_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "0,-10,24,42" + ), // Test extmul_high_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern:-7)])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_high_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "64,90,120,-154"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern: -7), + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_high_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "64,90,120,-154" + ), // Test extmul_low_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 256, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 256, 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_low_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "0,65536,24,42"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 256, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 256, 12, 14, 16, 18, 20, 22])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_low_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "0,65536,24,42" + ), // Test extmul_high_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 256])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 65535])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_high_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "64,90,120,16776960"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 256])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 65535, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_high_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "64,90,120,16776960" + ), // Test relaxed_swizzle. - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 4, 6, 5, 6, 4, 3, 2, 1, 9, 23, 24, 43, 20, 11, 6]) - let varB = function.constSimd128(value: [255, 3, 2, 1, 0, 4, 2, 3, 1, 14, 26, 11, 13, 7, 9, 6]) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.relaxed_swizzle) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16S, result, $0)} - } - }, "0,5,6,4,1,6,6,5,4,11,(23|0),24,20,2,9,3"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 4, 6, 5, 6, 4, 3, 2, 1, 9, 23, 24, 43, 20, 11, 6, + ]) + let varB = function.constSimd128(value: [ + 255, 3, 2, 1, 0, 4, 2, 3, 1, 14, 26, 11, 13, 7, 9, 6, + ]) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, + WasmSimd128IntegerBinOpKind.relaxed_swizzle) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16S, result, $0) + } + } + }, "0,5,6,4,1,6,6,5,4,11,(23|0),24,20,2,9,3" + ), // Test relaxed_q15mulr_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([16383, 16384, 32767, 65535, 65535, 32765, UInt16(bitPattern: -32768), 32768])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.relaxed_q15_mulr_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8192,8192,32766,0,1,1,(-32768|32767),-1"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 16383, 16384, 32767, 65535, 65535, 32765, + UInt16(bitPattern: -32768), 32768, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.relaxed_q15_mulr_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8192,8192,32766,0,1,1,(-32768|32767),-1" + ), // Test relaxed_dot_i8x16_i7x16_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 127, 127]) - let varB = function.constSimd128(value: - [10, 20, UInt8(bitPattern:-30), 40, 100, UInt8(bitPattern:-100), 50, UInt8(bitPattern:-50), 10, 20, UInt8(bitPattern:-30), 40, 50, UInt8(bitPattern:-50), 100, UInt8(bitPattern:-6)]) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.relaxed_dot_i8x16_i7x16_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "50,(70|838),(-100|1436),(-50|1998),(290|1998),(150|2966),(-50|3534),(11938|32767)"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 127, 127, + ]) + let varB = function.constSimd128(value: [ + 10, 20, UInt8(bitPattern: -30), 40, 100, UInt8(bitPattern: -100), 50, + UInt8(bitPattern: -50), 10, 20, UInt8(bitPattern: -30), 40, 50, + UInt8(bitPattern: -50), 100, UInt8(bitPattern: -6), + ]) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.relaxed_dot_i8x16_i7x16_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, + "50,(70|838),(-100|1436),(-50|1998),(290|1998),(150|2966),(-50|3534),(11938|32767)" + ), // Test extadd_pairwise_i8x16_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, UInt8(bitPattern:-1), UInt8(bitPattern:-2), UInt8(bitPattern:-3), UInt8(bitPattern:-4), 127, 127, - UInt8(bitPattern:-128), UInt8(bitPattern:-128), 10, UInt8(bitPattern:-10), 20, UInt8(bitPattern:-20)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "3,7,-3,-7,254,-256,0,0"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, UInt8(bitPattern: -1), UInt8(bitPattern: -2), + UInt8(bitPattern: -3), UInt8(bitPattern: -4), 127, 127, + UInt8(bitPattern: -128), UInt8(bitPattern: -128), 10, + UInt8(bitPattern: -10), 20, UInt8(bitPattern: -20), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "3,7,-3,-7,254,-256,0,0" + ), // Test extadd_pairwise_i8x16_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 2, 3, 4, 255, 255, 128, 128, 10, 20, 30, 40, 50, 60, 70, 80]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "3,7,510,256,30,70,110,150"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 255, 255, 128, 128, 10, 20, 30, 40, 50, 60, 70, 80, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "3,7,510,256,30,70,110,150" + ), // Test extadd_pairwise_i16x8_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, 2, 3, 4, 32767, 32767, UInt16(bitPattern: -32768), UInt16(bitPattern: -32768)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,7,65534,-65536"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, 2, 3, 4, 32767, 32767, UInt16(bitPattern: -32768), + UInt16(bitPattern: -32768), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,7,65534,-65536" + ), // Test extadd_pairwise_i16x8_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, 2, 3, 4, 65535, 65535, 32768, 32768])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,7,131070,65536"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([1, 2, 3, 4, 65535, 65535, 32768, 32768])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,7,131070,65536" + ), // Test abs // Note: abs(Int16.min) is Int16.min in Wasm. - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32767), 10, UInt16(bitPattern: -10)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.abs) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "1,1,0,-32768,32767,32767,10,10"), // abs(-32768) is -32768 in Wasm SIMD i16x8.abs + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, + UInt16(bitPattern: -32767), 10, UInt16(bitPattern: -10), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.abs) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "1,1,0,-32768,32767,32767,10,10" + ), // abs(-32768) is -32768 in Wasm SIMD i16x8.abs // Test neg // Note: neg(Int16.min) is Int16.min in Wasm. - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, 10, UInt16(bitPattern: -10), UInt16(bitPattern: -32767)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.neg) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,1,0,-32768,-32767,-10,10,32767"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, 10, + UInt16(bitPattern: -10), UInt16(bitPattern: -32767), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.neg) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,1,0,-32768,-32767,-10,10,32767" + ), // Test popcnt - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [0, 1, 3, 7, 15, 255, 127, UInt8(bitPattern:-1), 128, UInt8(bitPattern:-2), UInt8(bitPattern:-3), UInt8(bitPattern:-4), UInt8(bitPattern:-5), - UInt8(bitPattern:-6), UInt8(bitPattern:-7), UInt8(bitPattern:-8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.popcnt) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} // Popcnt result is unsigned - } - }, "0,1,2,3,4,8,7,8,1,7,7,6,7,6,6,5"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 0, 1, 3, 7, 15, 255, 127, UInt8(bitPattern: -1), 128, + UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), + UInt8(bitPattern: -5), + UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.popcnt) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } // Popcnt result is unsigned + } + }, "0,1,2,3,4,8,7,8,1,7,7,6,7,6,6,5" + ), // Test extend_low_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,2,3,4,5,6,7,8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,2,3,4,5,6,7,8" + ), // Test extend_high_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,-2,-3,-4,-5,-6,-7,-8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,-2,-3,-4,-5,-6,-7,-8" + ), // Test extend_low_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "255,2,3,4,5,6,7,8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "255,2,3,4,5,6,7,8" + ), // Test extend_high_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "255,254,253,252,251,250,249,248"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "255,254,253,252,251,250,249,248" + ), // Test all_true positive - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) - return [result, result] // hack to not confuse JS code extracting the result, as it always expects an array - } - }, "1,1"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) + return [result, result] // hack to not confuse JS code extracting the result, as it always expects an array + } + }, "1,1" + ), // Test all_true negative - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) - return [result, result] - } - }, "0,0"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) + return [result, result] + } + }, "0,0" + ), // Test bitmask - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [255, 200, 2, 230, 8, 16, 64, 127, 128, 129, 150, 180, 0, 1, 4, 8]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.bitmask) - return [result, result] - } - }, "3851,3851"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 255, 200, 2, 230, 8, 16, 64, 127, 128, 129, 150, 180, 0, 1, 4, 8, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.bitmask) + return [result, result] + } + }, "3851,3851" + ), // Test relaxed_trunc_f32x4_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-2147483648),1,-2,(2147483647|-2147483648)"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([ + 0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude, + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-2147483648),1,-2,(2147483647|-2147483648)" + ), // Test relaxed_trunc_f32x4_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),1,(0|-1),-1"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([ + 0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude, + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),1,(0|-1),-1" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test relaxed_trunc_f64x2_s_zero corner cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-2147483648),(2147483647|-2147483648),0,0"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-2147483648),(2147483647|-2147483648),0,0" + ), // Test relaxed_trunc_f64x2_s_zero standard cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "-3,7,0,0"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "-3,7,0,0" + ), // Test relaxed_trunc_f64x2_u_zero corner cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),(0|-1),0,0"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),(0|-1),0,0" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test relaxed_trunc_f64x2_u_zero standard cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),7,0,0"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),7,0,0" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test float add - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 1.5, 2.6, 3.7])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 5.9, 7.0, 8.1])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.add) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,7.40,9.60,11.80"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 1.5, 2.6, 3.7])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 5.9, 7.0, 8.1])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.add) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,7.40,9.60,11.80" + ), // Test float sub - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.sub) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,-4.40,4.40,4.40"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.sub) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,-4.40,4.40,4.40" + ), // Test float mul - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.mul) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,8.85,18.20,29.97"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.mul) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,8.85,18.20,29.97" + ), // Test float div - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.div) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,0.25,2.69,2.19"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.div) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,0.25,2.69,2.19" + ), // Test float min - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.min) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,NaN,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.min) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,NaN,NaN" + ), // Test float max - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.max) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,NaN,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.max) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,NaN,NaN" + ), // Test float pmin - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmin) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,7,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmin) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,7,NaN" + ), // Test float pmax - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmax) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,7,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmax) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,7,NaN" + ), // Test float relaxed_min - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.relaxed_min) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,(NaN|7),(NaN|3.70)"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, + WasmSimd128FloatBinOpKind.relaxed_min) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,(NaN|7),(NaN|3.70)" + ), // Test float relaxed_max - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.relaxed_max) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,(NaN|7),(NaN|3.70)"), - // Test madd - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) - let varC = function.constSimd128(value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) - let result = function.wasmSimd128FloatTernaryOp(varA, varB, varC, WasmSimd128Shape.f32x4, WasmSimd128FloatTernaryOpKind.madd) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"9.20,19.15,30.30,42.47"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, + WasmSimd128FloatBinOpKind.relaxed_max) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,(NaN|7),(NaN|3.70)" + ), + // Test madd + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) + let varC = function.constSimd128( + value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) + let result = function.wasmSimd128FloatTernaryOp( + varA, varB, varC, WasmSimd128Shape.f32x4, + WasmSimd128FloatTernaryOpKind.madd) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "9.20,19.15,30.30,42.47" + ), // Test nmadd - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) - let varC = function.constSimd128(value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) - let result = function.wasmSimd128FloatTernaryOp(varA, varB, varC, WasmSimd128Shape.f32x4, WasmSimd128FloatTernaryOpKind.nmadd) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"9.20,1.45,-7.50,-17.47"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) + let varC = function.constSimd128( + value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) + let result = function.wasmSimd128FloatTernaryOp( + varA, varB, varC, WasmSimd128Shape.f32x4, + WasmSimd128FloatTernaryOpKind.nmadd) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "9.20,1.45,-7.50,-17.47" + ), // Test relaxed_laneselect - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [34, 23, 27, 164, 4, 123, 34, 23, 27, 164, 4, 123, 34, 23, 27, 164]) - let varB = function.constSimd128(value: [42, 24, 160, 35, 24, 28, 42, 24, 160, 35, 24, 28, 42, 24, 160, 35]) - let varC = function.constSimd128(value: [255, 0, 128, 129, 20, 65, 255, 0, 128, 129, 20, 65, 255, 0, 128, 129]) - let result = function.wasmSimd128IntegerTernaryOp(varA, varB, varC, WasmSimd128Shape.i8x16, WasmSimd128IntegerTernaryOpKind.relaxed_laneselect) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} - } - },"34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164)"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 34, 23, 27, 164, 4, 123, 34, 23, 27, 164, 4, 123, 34, 23, 27, 164, + ]) + let varB = function.constSimd128(value: [ + 42, 24, 160, 35, 24, 28, 42, 24, 160, 35, 24, 28, 42, 24, 160, 35, + ]) + let varC = function.constSimd128(value: [ + 255, 0, 128, 129, 20, 65, 255, 0, 128, 129, 20, 65, 255, 0, 128, 129, + ]) + let result = function.wasmSimd128IntegerTernaryOp( + varA, varB, varC, WasmSimd128Shape.i8x16, + WasmSimd128IntegerTernaryOpKind.relaxed_laneselect) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } + } + }, + "34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164)" + ), // Test relaxed_dot_i8x16_i7x16_add_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [34, 23, 27, 124, 4, 123, 34, 23, 27, 124, 4, 123, 34, 23, 27, 124]) - let varB = function.constSimd128(value: [42, 24, 160, 35, 24, 28, 42, 24, 120, 35, 24, 28, 42, 24, 120, 35]) - let varC = function.constSimd128(value: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]) // i32x4 vector in fact - let result = function.wasmSimd128IntegerTernaryOp(varA, varB, varC, WasmSimd128Shape.i32x4, WasmSimd128IntegerTernaryOpKind.relaxed_dot_i8x16_i7x16_add_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - },"(3729|10641),5522,11123,9564") + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 34, 23, 27, 124, 4, 123, 34, 23, 27, 124, 4, 123, 34, 23, 27, 124, + ]) + let varB = function.constSimd128(value: [ + 42, 24, 160, 35, 24, 28, 42, 24, 120, 35, 24, 28, 42, 24, 120, 35, + ]) + let varC = function.constSimd128(value: [ + 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, + ]) // i32x4 vector in fact + let result = function.wasmSimd128IntegerTernaryOp( + varA, varB, varC, WasmSimd128Shape.i32x4, + WasmSimd128IntegerTernaryOpKind.relaxed_dot_i8x16_i7x16_add_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(3729|10641),5522,11123,9564" + ), ] let module = b.buildWasmModule { wasmModule in - for(createWasmFunction, _) in testCases { + for (createWasmFunction, _) in testCases { createWasmFunction(wasmModule) } } @@ -2643,13 +3694,17 @@ class WasmFoundationTests: XCTestCase { let rawValues = b.callMethod(module.getExportedMethod(at: i), on: module.loadExports()) - b.callFunction(print, withArgs: - [b.callMethod("join", on: b.callMethod("map", on:rawValues, withArgs: [setFormat]))] + b.callFunction( + print, + withArgs: [ + b.callMethod( + "join", on: b.callMethod("map", on: rawValues, withArgs: [setFormat])) + ] ) } let jsProg = fuzzer.lifter.lift(b.finalize()) - let expected = testCases.map {$0.1}.joined(separator: "\n") + "\n" + let expected = testCases.map { $0.1 }.joined(separator: "\n") + "\n" testForOutputRegex(program: jsProg, runner: runner, outputPattern: expected) } @@ -2689,7 +3744,8 @@ class WasmFoundationTests: XCTestCase { function.wasmBuildLoop(with: [] => [], args: []) { label, args in XCTAssert(b.type(of: label).Is(.anyLabel)) let result = function.wasmi32BinOp(ctr, one, binOpKind: .Add) - let varUpdate = function.wasmi64BinOp(variable, function.consti64(2), binOpKind: .Add) + let varUpdate = function.wasmi64BinOp( + variable, function.consti64(2), binOpKind: .Add) function.wasmReassign(variable: ctr, to: result) function.wasmReassign(variable: variable, to: varUpdate) let comp = function.wasmi32CompareOp(ctr, max, using: .Lt_s) @@ -2722,22 +3778,30 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in - let loopResult = function.wasmBuildLoop(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: args) { loopLabel, loopArgs in - let incFirst = function.wasmi32BinOp(loopArgs[0], function.consti32(1), binOpKind: .Add) - let incSecond = function.wasmi32BinOp(loopArgs[1], function.consti32(2), binOpKind: .Add) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in + let loopResult = function.wasmBuildLoop( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: args + ) { loopLabel, loopArgs in + let incFirst = function.wasmi32BinOp( + loopArgs[0], function.consti32(1), binOpKind: .Add) + let incSecond = function.wasmi32BinOp( + loopArgs[1], function.consti32(2), binOpKind: .Add) let condition = function.wasmi32CompareOp(incFirst, incSecond, using: .Gt_s) function.wasmBranchIf(condition, to: loopLabel, args: [incFirst, incSecond]) return [incFirst, incSecond] } - function.wasmBuildIfElse(function.wasmi32CompareOp(loopResult[1], function.consti32(20), using: .Ne)) { label, args in + function.wasmBuildIfElse( + function.wasmi32CompareOp(loopResult[1], function.consti32(20), using: .Ne) + ) { label, args in function.wasmUnreachable() } return [loopResult[0]] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(10), b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(10), b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -2756,8 +3820,8 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in let variable = args[0] - let condVariable = function.consti32(10); - let result = function.consti32(0); + let condVariable = function.consti32(10) + let result = function.consti32(0) let comp = function.wasmi32CompareOp(variable, condVariable, using: .Lt_s) @@ -2775,7 +3839,8 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1337)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1337)]) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) @@ -2792,12 +3857,16 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + function, label, args in let inputs = [args[1], function.consti64(3)] - function.wasmBuildIfElse(args[0], signature: [.wasmi64, .wasmi64] => [], args: inputs, inverted: false) { label, ifArgs in + function.wasmBuildIfElse( + args[0], signature: [.wasmi64, .wasmi64] => [], args: inputs, inverted: false + ) { label, ifArgs in function.wasmReturn(ifArgs[0]) - } elseBody: {label, ifArgs in - function.wasmReturn(function.wasmi64BinOp(ifArgs[0], ifArgs[1], binOpKind: .Shl)) + } elseBody: { label, ifArgs in + function.wasmReturn( + function.wasmi64BinOp(ifArgs[0], ifArgs[1], binOpKind: .Shl)) } return [function.consti64(-1)] } @@ -2805,9 +3874,12 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - var wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1), b.loadBigInt(42)]) + var wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, + withArgs: [b.loadInt(1), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0), b.loadBigInt(1)]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0), b.loadBigInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -2822,11 +3894,14 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: [args[1]], inverted: false) { ifLabel, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: [args[1]], inverted: false + ) { ifLabel, ifArgs in function.wasmBranchIf(ifArgs[0], to: ifLabel) function.wasmReturn(function.consti32(100)) - } elseBody: {elseLabel, ifArgs in + } elseBody: { elseLabel, ifArgs in function.wasmBranchIf(ifArgs[0], to: elseLabel) function.wasmReturn(function.consti32(200)) } @@ -2837,15 +3912,15 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let runAndPrint = {args in + let runAndPrint = { args in let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: args) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) } - runAndPrint([b.loadInt(1), b.loadInt(0)]) // 100 - runAndPrint([b.loadInt(1), b.loadInt(1)]) // 300 - runAndPrint([b.loadInt(0), b.loadInt(0)]) // 200 - runAndPrint([b.loadInt(0), b.loadInt(1)]) // 300 + runAndPrint([b.loadInt(1), b.loadInt(0)]) // 100 + runAndPrint([b.loadInt(1), b.loadInt(1)]) // 300 + runAndPrint([b.loadInt(0), b.loadInt(0)]) // 200 + runAndPrint([b.loadInt(0), b.loadInt(1)]) // 300 let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -2860,9 +3935,11 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - let blockResult = function.wasmBuildIfElseWithResult(args[0], signature: [] => [.wasmi64, .wasmi64], args: []) {label, args in + let blockResult = function.wasmBuildIfElseWithResult( + args[0], signature: [] => [.wasmi64, .wasmi64], args: [] + ) { label, args in return [function.consti64(123), function.consti64(10)] - } elseBody: {label, args in + } elseBody: { label, args in return [function.consti64(321), function.consti64(10)] } let sum = function.wasmi64BinOp(blockResult[0], blockResult[1], binOpKind: .Add) @@ -2870,9 +3947,11 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let outTrue = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let outTrue = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: outTrue)]) - let outFalse = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let outFalse = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: outFalse)]) let prog = b.finalize() @@ -2896,8 +3975,10 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { _, _ in - let one = function.wasmJsCall(function: jsReturnOne, withArgs: [], + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { + _, _ in + let one = function.wasmJsCall( + function: jsReturnOne, withArgs: [], withWasmSignature: [] => [.wasmi32])! function.wasmReturn(one) } @@ -2912,13 +3993,17 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let out0 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let out0 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out0)]) - let out5 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(5)]) + let out5 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(5)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out5)]) - let out1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let out1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out1)]) - let out3 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(3)]) + let out3 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(3)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out3)]) let prog = b.finalize() @@ -2973,8 +4058,10 @@ class WasmFoundationTests: XCTestCase { function.wasmBuildLegacyTryVoid { label in XCTAssert(b.type(of: label).Is(.anyLabel)) // Manually set the availableTypes here for testing. - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) - function.wasmJsCall(function: functionA, withArgs: [], withWasmSignature: wasmSignature) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, availableTypes: WeightedList([])) + function.wasmJsCall( + function: functionA, withArgs: [], withWasmSignature: wasmSignature) function.wasmUnreachable() } catchAllBody: { label in function.wasmReturn(function.consti64(123)) @@ -3013,16 +4100,26 @@ class WasmFoundationTests: XCTestCase { b.buildIfElse(supportsJSTag) { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) - function.wasmJsCall(function: functionA, withArgs: [], withWasmSignature: wasmSignature) - function.wasmUnreachable() - }, catchClauses: [(tag: jstag, body: { label, exception, args in - function.wasmReturn(function.consti64(123)) - })], catchAllBody: { label in - function.wasmUnreachable() - }) + function.wasmBuildLegacyTryVoid( + body: { label in + XCTAssert(b.type(of: label).Is(.anyLabel)) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, availableTypes: WeightedList([])) + function.wasmJsCall( + function: functionA, withArgs: [], withWasmSignature: wasmSignature) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: jstag, + body: { label, exception, args in + function.wasmReturn(function.consti64(123)) + } + ) + ], + catchAllBody: { label in + function.wasmUnreachable() + }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3068,21 +4165,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) - function.WasmBuildThrow(tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) - function.wasmUnreachable() - }, catchClauses: [ - (tag: otherTag, body: { label, exception, args in + function.wasmBuildLegacyTryVoid( + body: { label in + XCTAssert(b.type(of: label).Is(.anyLabel)) + function.WasmBuildThrow( + tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: otherTag, + body: { label, exception, args in + function.wasmUnreachable() + } + ), + ( + tag: throwTag, + body: { label, exception, args in + let result = function.wasmi64BinOp( + args[0], function.extendi32Toi64(args[1], isSigned: true), + binOpKind: .Add) + function.wasmReturn(result) + } + ), + ], + catchAllBody: { label in function.wasmUnreachable() - }), - (tag: throwTag, body: { label, exception, args in - let result = function.wasmi64BinOp(args[0], function.extendi32Toi64(args[1], isSigned: true), binOpKind: .Add) - function.wasmReturn(result) }) - ], catchAllBody: { label in - function.wasmUnreachable() - }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3105,11 +4214,18 @@ class WasmFoundationTests: XCTestCase { let tag = b.createWasmTag(parameterTypes: []) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { tryLabel in - function.WasmBuildThrow(tag: tag, inputs: []) - }, catchClauses: [(tag: tag, body: { catchLabel, exceptionLabel, args in - function.wasmBranch(to: catchLabel) - })]) + function.wasmBuildLegacyTryVoid( + body: { tryLabel in + function.WasmBuildThrow(tag: tag, inputs: []) + }, + catchClauses: [ + ( + tag: tag, + body: { catchLabel, exceptionLabel, args in + function.wasmBranch(to: catchLabel) + } + ) + ]) return [function.consti32(42)] } } @@ -3151,7 +4267,6 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n") } - func testTryCatchWasmExceptionNominal() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -3187,23 +4302,37 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, param in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildIfElse(param[0], hint: .None) { _, _ in - function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) - } elseBody: { _, _ in - function.WasmBuildThrow(tag: importedTag, inputs: [function.consti32(123)]) - } - function.wasmUnreachable() - }, catchClauses: [ - (tag: importedTag, body: { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(1), binOpKind: .Add)) - }), - (tag: definedTag, body: { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(4), binOpKind: .Add)) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildIfElse(param[0], hint: .None) { _, _ in + function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) + } elseBody: { _, _ in + function.WasmBuildThrow( + tag: importedTag, inputs: [function.consti32(123)]) + } + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: importedTag, + body: { label, exception, args in + function.wasmReturn( + function.wasmi32BinOp( + args[0], function.consti32(1), binOpKind: .Add)) + } + ), + ( + tag: definedTag, + body: { label, exception, args in + function.wasmReturn( + function.wasmi32BinOp( + args[0], function.consti32(4), binOpKind: .Add)) + } + ), + ], + catchAllBody: { label in + function.wasmUnreachable() }) - ], catchAllBody: { label in - function.wasmUnreachable() - }) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3241,18 +4370,28 @@ class WasmFoundationTests: XCTestCase { let argI64 = function.consti64(321) let signature = [.wasmi64, .wasmi32] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - function.wasmBuildLegacyTryWithResult(signature: signature, signatureDef: signatureDef, - args: [argI64, argI32], body: { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) - XCTAssertEqual(b.type(of: args[0]), .wasmi64) - XCTAssertEqual(b.type(of: args[1]), .wasmi32) - function.WasmBuildThrow(tag: tag, inputs: args) - return [] - }, catchClauses: [(tag: tag, body: { label, exception, args in - let result = function.wasmi64BinOp(args[0], function.extendi32Toi64(args[1], isSigned: true), binOpKind: .Add) - function.wasmReturn(result) - return [] - })]) + function.wasmBuildLegacyTryWithResult( + signature: signature, signatureDef: signatureDef, + args: [argI64, argI32], + body: { label, args in + XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssertEqual(b.type(of: args[0]), .wasmi64) + XCTAssertEqual(b.type(of: args[1]), .wasmi32) + function.WasmBuildThrow(tag: tag, inputs: args) + return [] + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + let result = function.wasmi64BinOp( + args[0], function.extendi32Toi64(args[1], isSigned: true), + binOpKind: .Add) + function.wasmReturn(result) + return [] + } + ) + ]) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3284,31 +4423,49 @@ class WasmFoundationTests: XCTestCase { let contant42 = function.consti64(42) let signature = [.wasmi32] => [.wasmi32, .wasmi64] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let result = function.wasmBuildLegacyTryWithResult(signature: signature, - signatureDef: signatureDef, args: args, body: { label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in - function.WasmBuildThrow(tag: tagVoid, inputs: []) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq)) { _, _ in - function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(100)]) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq)) { _, _ in - function.WasmBuildThrow(tag: tagi32Other, inputs: [function.consti32(200)]) - } - return [args[0], contant42] - }, catchClauses: [ - (tagi32, {label, exception, args in + let result = function.wasmBuildLegacyTryWithResult( + signature: signature, + signatureDef: signatureDef, args: args, + body: { label, args in + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in + function.WasmBuildThrow(tag: tagVoid, inputs: []) + } + function.wasmBuildIfElse( + function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq) + ) { _, _ in + function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(100)]) + } + function.wasmBuildIfElse( + function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq) + ) { _, _ in + function.WasmBuildThrow( + tag: tagi32Other, inputs: [function.consti32(200)]) + } return [args[0], contant42] - }), - (tagi32Other, {label, exception, args in - let value = function.wasmi32BinOp(args[0], function.consti32(2), binOpKind: .Add) - function.wasmBranch(to: label, args: [value, contant42]) - return [function.consti32(-1), function.consti64(-1)] - }), - ], catchAllBody: { _ in - return [function.consti32(900), contant42] - }) - function.wasmBuildIfElse(function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None) { _, _ in + }, + catchClauses: [ + ( + tagi32, + { label, exception, args in + return [args[0], contant42] + } + ), + ( + tagi32Other, + { label, exception, args in + let value = function.wasmi32BinOp( + args[0], function.consti32(2), binOpKind: .Add) + function.wasmBranch(to: label, args: [value, contant42]) + return [function.consti32(-1), function.consti64(-1)] + } + ), + ], + catchAllBody: { _ in + return [function.consti32(900), contant42] + }) + function.wasmBuildIfElse( + function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None + ) { _, _ in function.wasmUnreachable() } return [result[0]] @@ -3321,18 +4478,20 @@ class WasmFoundationTests: XCTestCase { // to the EndTry block. At the end of the wasm function it performs a wasm return of the // result of the EndTry. for (input, expected) in [ - // input 0 throws tagVoid which is not caught, so the catchAllBody returns 900. - (0, 900), - // input 1 throws tagi32(100) which is caught by a catch clause that returns the - // tag argument. - (1, 100), - // input 2 throws tagi32Other(200) which is caught by a catch clause that branches - // to the end of its block adding 2 to the tag argument. - (2, 202), - // input 3 doesn't throw anything, the try body returns the value directly, meaning - // the value "falls-through" from the try body to the endTry operation. - (3, 3)] { - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(input))]) + // input 0 throws tagVoid which is not caught, so the catchAllBody returns 900. + (0, 900), + // input 1 throws tagi32(100) which is caught by a catch clause that returns the + // tag argument. + (1, 100), + // input 2 throws tagi32Other(200) which is caught by a catch clause that branches + // to the end of its block adding 2 to the tag argument. + (2, 202), + // input 3 doesn't throw anything, the try body returns the value directly, meaning + // the value "falls-through" from the try body to the endTry operation. + (3, 3), + ] { + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(input))]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) expectedString += "\(expected)\n" } @@ -3372,22 +4531,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { tryLabel in - // Even though we have a try-catch_all, the delegate "skips" this catch block. The delegate acts as - // if the exception was thrown by the block whose label is passed into it. - function.wasmBuildLegacyTryVoid(body: { unusedLabel in - let val = function.consti32(42) - function.wasmBuildLegacyTryDelegate(with: [.wasmi32] => [], args: [val], body: {label, args in - function.WasmBuildThrow(tag: tag, inputs: args) - }, delegate: tryLabel) + function.wasmBuildLegacyTryVoid( + body: { tryLabel in + // Even though we have a try-catch_all, the delegate "skips" this catch block. The delegate acts as + // if the exception was thrown by the block whose label is passed into it. + function.wasmBuildLegacyTryVoid( + body: { unusedLabel in + let val = function.consti32(42) + function.wasmBuildLegacyTryDelegate( + with: [.wasmi32] => [], args: [val], + body: { label, args in + function.WasmBuildThrow(tag: tag, inputs: args) + }, delegate: tryLabel) + function.wasmUnreachable() + }, + catchAllBody: { label in + function.wasmUnreachable() + }) function.wasmUnreachable() - }, catchAllBody: { label in - function.wasmUnreachable() - }) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3412,10 +4582,13 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in function.wasmBuildBlock(with: [] => [], args: []) { label, _ in let val = function.consti32(42) - let result = function.wasmBuildLegacyTryDelegateWithResult(with: [.wasmi32] => [.wasmi32, .wasmi32], args: [val], body: {tryLabel, args in - return [args[0], function.consti32(10)] - }, delegate: label) - function.wasmReturn(function.wasmi32BinOp(result[0], result[1], binOpKind: .Add)) + let result = function.wasmBuildLegacyTryDelegateWithResult( + with: [.wasmi32] => [.wasmi32, .wasmi32], args: [val], + body: { tryLabel, args in + return [args[0], function.consti32(10)] + }, delegate: label) + function.wasmReturn( + function.wasmi32BinOp(result[0], result[1], binOpKind: .Add)) } function.wasmUnreachable() return [function.consti32(-1)] @@ -3457,16 +4630,30 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmBuildLegacyRethrow(exception) - })]) - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmBuildLegacyRethrow(exception) + } + ) + ]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3508,23 +4695,46 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - }, catchClauses: [(tag: tag, body: { label, outerException, args in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(456)]) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, innerException, args in - // There are two "active" exceptions: - // outerException: [123: i32] - // innerException: [456: i32] - function.wasmBuildLegacyRethrow(outerException) - })]) - })]) - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, outerException, args in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow( + tag: tag, inputs: [function.consti32(456)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: tag, + body: { label, innerException, args in + // There are two "active" exceptions: + // outerException: [123: i32] + // innerException: [456: i32] + function.wasmBuildLegacyRethrow( + outerException) + } + ) + ]) + } + ) + ]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3548,9 +4758,11 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmf64]) { function, _, _ in let argI32 = function.consti32(12345) let argF64 = function.constf64(543.21) - function.wasmBuildBlock(with: [.wasmi32, .wasmf64] => [], args: [argI32, argF64]) { blockLabel, args in + function.wasmBuildBlock(with: [.wasmi32, .wasmf64] => [], args: [argI32, argF64]) { + blockLabel, args in XCTAssertEqual(args.count, 2) - let result = function.wasmf64BinOp(function.converti32Tof64(args[0], isSigned: true), args[1], binOpKind: .Add) + let result = function.wasmf64BinOp( + function.converti32Tof64(args[0], isSigned: true), args[1], binOpKind: .Add) function.wasmReturn(result) } function.wasmUnreachable() @@ -3574,10 +4786,13 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - let blockResult = function.wasmBuildBlockWithResults(with: [.wasmi32] => [.wasmi64, .wasmi32], args: [function.consti32(1234)]) { blockLabel, args in + let blockResult = function.wasmBuildBlockWithResults( + with: [.wasmi32] => [.wasmi64, .wasmi32], args: [function.consti32(1234)] + ) { blockLabel, args in return [function.extendi32Toi64(args[0], isSigned: true), args[0]] } - let sum = function.wasmi64BinOp(blockResult[0], + let sum = function.wasmi64BinOp( + blockResult[0], function.extendi32Toi64(blockResult[1], isSigned: true), binOpKind: .Add) return [sum] } @@ -3599,19 +4814,30 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let blockResult = function.wasmBuildBlockWithResults(with: [.wasmi32] => [.wasmi32, .wasmi64], args: args) { blockLabel, blockArgs in - function.wasmBranchIf(blockArgs[0], to: blockLabel, args: [function.wasmi32BinOp(blockArgs[0], args[0], binOpKind: .Add), function.consti64(1)]) - function.wasmBranch(to: blockLabel, args: [function.consti32(12345), function.consti64(54321)]) + let blockResult = function.wasmBuildBlockWithResults( + with: [.wasmi32] => [.wasmi32, .wasmi64], args: args + ) { blockLabel, blockArgs in + function.wasmBranchIf( + blockArgs[0], to: blockLabel, + args: [ + function.wasmi32BinOp(blockArgs[0], args[0], binOpKind: .Add), + function.consti64(1), + ]) + function.wasmBranch( + to: blockLabel, args: [function.consti32(12345), function.consti64(54321)]) return [function.consti32(-1), function.consti64(0)] } - let sum = function.wasmi32BinOp(blockResult[0], function.wrapi64Toi32(blockResult[1]), binOpKind: .Add) + let sum = function.wasmi32BinOp( + blockResult[0], function.wrapi64Toi32(blockResult[1]), binOpKind: .Add) return [sum] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) let prog = b.finalize() @@ -3637,11 +4863,14 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) - let wasmOut3 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-1)]) + let wasmOut3 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut3)]) let prog = b.finalize() @@ -3656,29 +4885,44 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + function, label, args in // Fuzzilli doesn't have support for handling stack-polymorphic cases after // non-returning instructions like br_table or return. let dummy = [function.consti64(-1), function.consti64(-1)] - let block1Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label1, _ in - let block2Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label2, _ in - let block3Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label3, _ in - function.wasmBranchTable(on: args[0], labels: [label1, label2, label3], + let block1Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label1, _ in + let block2Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label2, _ in + let block3Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label3, _ in + function.wasmBranchTable( + on: args[0], labels: [label1, label2, label3], args: [args[1], function.extendi32Toi64(args[0], isSigned: false)]) return dummy } - function.wasmReturn(function.wasmi64BinOp(block3Result[0], block3Result[1], binOpKind: .Add)) + function.wasmReturn( + function.wasmi64BinOp(block3Result[0], block3Result[1], binOpKind: .Add) + ) return dummy } - function.wasmReturn(function.wasmi64BinOp(block2Result[0], function.consti64(2), binOpKind: .Add)) + function.wasmReturn( + function.wasmi64BinOp( + block2Result[0], function.consti64(2), binOpKind: .Add)) return dummy } - return [function.wasmi64BinOp(block1Result[0], function.consti64(1), binOpKind: .Add)] + return [ + function.wasmi64BinOp(block1Result[0], function.consti64(1), binOpKind: .Add) + ] } } let exports = module.loadExports() for val in [0, 1, 2, 100] { - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(val)), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) } @@ -3696,20 +4940,28 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - let blockResult = function.wasmBuildTryTable(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi32], args: [args[0], function.consti64(1234)], catches: []) { tryLabel, tryArgs in - let isZero = function.wasmi32CompareOp(tryArgs[0], function.consti32(0), using: .Eq) - function.wasmBranchIf(isZero, to: tryLabel, args: [function.consti64(10), function.consti32(20)]) + let blockResult = function.wasmBuildTryTable( + with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi32], + args: [args[0], function.consti64(1234)], catches: [] + ) { tryLabel, tryArgs in + let isZero = function.wasmi32CompareOp( + tryArgs[0], function.consti32(0), using: .Eq) + function.wasmBranchIf( + isZero, to: tryLabel, args: [function.consti64(10), function.consti32(20)]) return [tryArgs[1], tryArgs[0]] } - let sum = function.wasmi64BinOp(blockResult[0], + let sum = function.wasmi64BinOp( + blockResult[0], function.extendi32Toi64(blockResult[1], isSigned: true), binOpKind: .Add) return [sum] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3728,8 +4980,13 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in function.wasmBuildBlock(with: [] => [], args: []) { catchAllNoRefLabel, _ in - let catchNoRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchNoRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchNoRefLabel, catchAllNoRefLabel], catches: [.NoRef, .AllNoRef]) { _, _ in + let catchNoRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchNoRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchNoRefLabel, catchAllNoRefLabel], + catches: [.NoRef, .AllNoRef] + ) { _, _ in function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) } elseBody: { _, _ in @@ -3746,9 +5003,11 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3766,9 +5025,15 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchAllRefLabel, _ in - let catchRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchRefLabel, catchAllRefLabel], catches: [.Ref, .AllRef]) { _, _ in + function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { + catchAllRefLabel, _ in + let catchRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchRefLabel, catchAllRefLabel], + catches: [.Ref, .AllRef] + ) { _, _ in function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) } elseBody: { _, _ in @@ -3786,9 +5051,11 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3805,15 +5072,18 @@ class WasmFoundationTests: XCTestCase { let tagFromJS = b.createWasmTag(parameterTypes: [defineInWasm ? .wasmi64 : .wasmi32]) let moduleThrow = b.buildWasmModule { wasmModule in - let tagFromWasm = wasmModule.addTag(parameterTypes: [defineInWasm ? .wasmi32 : .wasmi64]) + let tagFromWasm = wasmModule.addTag(parameterTypes: [defineInWasm ? .wasmi32 : .wasmi64] + ) wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in - function.WasmBuildThrow(tag: defineInWasm ? tagFromWasm : tagFromJS, inputs: [args[0]]) + function.WasmBuildThrow( + tag: defineInWasm ? tagFromWasm : tagFromJS, inputs: [args[0]]) return [] } // Unused function that forces usage of the js tag if not used in the previous function. // (So that both get exported.) wasmModule.addWasmFunction(with: [.wasmi64] => []) { function, label, args in - function.WasmBuildThrow(tag: defineInWasm ? tagFromJS : tagFromWasm, inputs: [args[0]]) + function.WasmBuildThrow( + tag: defineInWasm ? tagFromJS : tagFromWasm, inputs: [args[0]]) return [] } } @@ -3823,21 +5093,29 @@ class WasmFoundationTests: XCTestCase { let wasmTagExported = b.getProperty("wex0", of: moduleThrow.loadExports()) // The re-exported tag is prefixed with the `i` for `imported`. let jsTagExported = b.getProperty("iwex0", of: moduleThrow.loadExports()) - let wasmTagExportedType = ILType.object(ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi32 : .wasmi64])) - let jsTagExportedType = ILType.object(ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi64 : .wasmi32])) + let wasmTagExportedType = ILType.object( + ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi32 : .wasmi64])) + let jsTagExportedType = ILType.object( + ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi64 : .wasmi32])) XCTAssertEqual(b.type(of: wasmTagExported), wasmTagExportedType) XCTAssertEqual(b.type(of: jsTagExported), jsTagExportedType) let tagToUse = defineInWasm ? wasmTagExported : jsTagExported let moduleCatch = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let catchNoRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchNoRefLabel, _ in + let catchNoRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchNoRefLabel, _ in // The usage of tagToUse in the try_table below is the interesting part of // this test case: It triggers an import of the tag exported by the previous // module and expects that we have all the correct information about it // (including the tag's parameter types.) - function.wasmBuildTryTable(with: [] => [], args: [tagToUse, catchNoRefLabel], catches: [.NoRef]) { _, _ in - function.wasmJsCall(function: throwFct, withArgs: [function.consti32(42)], withWasmSignature: [.wasmi32] => []) + function.wasmBuildTryTable( + with: [] => [], args: [tagToUse, catchNoRefLabel], catches: [.NoRef] + ) { _, _ in + function.wasmJsCall( + function: throwFct, withArgs: [function.consti32(42)], + withWasmSignature: [.wasmi32] => []) return [] } return [function.consti32(-1)] @@ -3870,7 +5148,9 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() // Assumption: All types apart from bottom (null) & shared types are supported in the JS API. - let supportedTypes = WasmAbstractHeapType.allNonBottomTypes().map {ILType.wasmRef($0, nullability: true)} + let supportedTypes = WasmAbstractHeapType.allNonBottomTypes().map { + ILType.wasmRef($0, nullability: true) + } b.createWasmTag(parameterTypes: supportedTypes) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog, withOptions: [.includeComments]) @@ -3895,16 +5175,23 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in // Inner function that throws, catches and then rethrows the value. - let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchRefLabel], catches: [.Ref]) { _, _ in + let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { + function, label, args in + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchRefLabel], catches: [.Ref] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) return [] } return [function.consti32(0), function.wasmRefNull(type: .wasmExnRef())] } // Print the caught i32 value. - function.wasmJsCall(function: printInteger, withArgs: [caughtValues[0]], withWasmSignature: [.wasmi32] => []) + function.wasmJsCall( + function: printInteger, withArgs: [caughtValues[0]], + withWasmSignature: [.wasmi32] => []) // To rethrow the exception, perform a throw_ref with the exnref. function.wasmBuildThrowRef(exception: caughtValues[1]) return [] @@ -3912,9 +5199,14 @@ class WasmFoundationTests: XCTestCase { // Outer function that calls the inner function and catches the rethrown exception. wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.NoRef]) { _, _ in - function.wasmCallDirect(signature: [.wasmi32] => [], function: callee, functionArgs: args) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.NoRef] + ) { _, _ in + function.wasmCallDirect( + signature: [.wasmi32] => [], function: callee, functionArgs: args) return [] } return [function.consti32(-1)] @@ -3924,7 +5216,8 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -3970,11 +5263,16 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - [function.wasmSelect(on: args[0], - trueValue: function.consti64(123), falseValue: function.consti64(321))] + [ + function.wasmSelect( + on: args[0], + trueValue: function.consti64(123), falseValue: function.consti64(321)) + ] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmExternRef(), .wasmExternRef()] => [.wasmExternRef()]) { function, label, args in + wasmModule.addWasmFunction( + with: [.wasmi32, .wasmExternRef(), .wasmExternRef()] => [.wasmExternRef()] + ) { function, label, args in [function.wasmSelect(on: args[0], trueValue: args[1], falseValue: args[2])] } } @@ -3982,16 +5280,20 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") // Select with i64. - var wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + var wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) // Select with externref. let hello = b.loadString("Hello") let world = b.loadString("World") - wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(1), hello, world]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(1), hello, world]) b.callFunction(outputFunc, withArgs: [wasmOut]) - wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(0), hello, world]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(0), hello, world]) b.callFunction(outputFunc, withArgs: [wasmOut]) let prog = b.finalize() @@ -4011,8 +5313,10 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayA = function.wasmArrayNewFixed(arrayType: arrayi32, elements: [function.consti32(123)]) - let arrayB = function.wasmArrayNewFixed(arrayType: arrayi32, elements: [function.consti32(-321)]) + let arrayA = function.wasmArrayNewFixed( + arrayType: arrayi32, elements: [function.consti32(123)]) + let arrayB = function.wasmArrayNewFixed( + arrayType: arrayi32, elements: [function.consti32(-321)]) let array = function.wasmSelect(on: args[0], trueValue: arrayA, falseValue: arrayB) return [function.wasmArrayGet(array: array, index: function.consti32(0))] } @@ -4020,9 +5324,11 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) let prog = b.finalize() @@ -4040,26 +5346,35 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let printMessage = b.buildPlainFunction(with: .parameters(.integer)) { args in - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.loadString("This should never be called!"))]) + b.callFunction( + outputFunc, + withArgs: [ + b.callMethod("toString", on: b.loadString("This should never be called!")) + ]) } let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in + let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { + function, label, args in return [] } // Outer function that is supposed to call callee. wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in // This direct call accidentally got wrongly lifted to calling the imported js function (printMessage). - function.wasmCallDirect(signature: [.wasmi32] => [], function: callee, functionArgs: args) + function.wasmCallDirect( + signature: [.wasmi32] => [], function: callee, functionArgs: args) function.wasmReturn(function.consti32(42)) // This call is unreachable and only exists here to trigger the import of the printMessage function. - function.wasmJsCall(function: printMessage, withArgs: [args[0]], withWasmSignature: [.wasmi32] => []) + function.wasmJsCall( + function: printMessage, withArgs: [args[0]], withWasmSignature: [.wasmi32] => [] + ) return [function.consti32(-1)] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -4079,8 +5394,11 @@ class WasmFoundationTests: XCTestCase { let moduleA = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in function.wasmReturn(function.consti64(-1)) - return [function.wasmJsCall(function: jsFunction, - withArgs: [], withWasmSignature: [] => [.wasmi64])!] + return [ + function.wasmJsCall( + function: jsFunction, + withArgs: [], withWasmSignature: [] => [.wasmi64])! + ] } } @@ -4088,14 +5406,18 @@ class WasmFoundationTests: XCTestCase { let reexportedJSFct = b.getProperty("iw0", of: exportsA) // Test that the type system knows about the re-exported function, so that it is // discoverable by code generators. - XCTAssert(b.type(of: exportsA).Is( - .object(ofGroup: nil, withProperties: [], withMethods: ["w0", "iw0"]))) + XCTAssert( + b.type(of: exportsA).Is( + .object(ofGroup: nil, withProperties: [], withMethods: ["w0", "iw0"]))) XCTAssert(b.type(of: reexportedJSFct).Is(.function([] => .bigint))) let moduleB = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - [function.wasmJsCall(function: reexportedJSFct, - withArgs: [], withWasmSignature: [] => [.wasmi64])!] + [ + function.wasmJsCall( + function: reexportedJSFct, + withArgs: [], withWasmSignature: [] => [.wasmi64])! + ] } } let exportsB = moduleB.loadExports() @@ -4114,10 +5436,10 @@ class WasmFoundationTests: XCTestCase { func testDefineElementSegments() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in - let f1 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} - let f2 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} + let f1 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } + let f2 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } wasmModule.addElementSegment(elements: []) wasmModule.addElementSegment(elements: [f1]) wasmModule.addElementSegment(elements: [f1, f2]) @@ -4129,9 +5451,9 @@ class WasmFoundationTests: XCTestCase { func testDropElementSegments() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in - let function = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} + let function = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } let segment = wasmModule.addElementSegment(elements: [function]) wasmModule.addWasmFunction(with: [] => []) { f, _, _ in f.wasmDropElementSegment(elementSegment: segment) @@ -4145,18 +5467,26 @@ class WasmFoundationTests: XCTestCase { func wasmTableInit(isTable64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { module in - let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(1)]} - let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} - let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} + let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(1)] + } + let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(2)] + } + let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(3)] + } // TODO(pawkra): add shared ref variant. - module.addTable(elementType: .wasmFuncRef(), + module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], @@ -4165,20 +5495,28 @@ class WasmFoundationTests: XCTestCase { let elemSegment2 = module.addElementSegment(elements: [f3, f3, f1, f2]) module.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in - let tableOffset = { (i: Int) in isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i))} - f.wasmTableInit(elementSegment: elemSegment2, table: table2, tableOffset: tableOffset(5), elementSegmentOffset: f.consti32(2), nrOfElementsToUpdate: f.consti32(2)) + let tableOffset = { (i: Int) in + isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i)) + } + f.wasmTableInit( + elementSegment: elemSegment2, table: table2, tableOffset: tableOffset(5), + elementSegmentOffset: f.consti32(2), nrOfElementsToUpdate: f.consti32(2)) let callIndirect = { (table: Variable, idx: Int) in let idxVar = isTable64 ? f.consti64(Int64(idx)) : f.consti32(Int32(idx)) - return f.wasmCallIndirect(signature: [] => [.wasmi64], table: table, functionArgs: [], tableIndex: idxVar) + return f.wasmCallIndirect( + signature: [] => [.wasmi64], table: table, functionArgs: [], + tableIndex: idxVar) } - return callIndirect(table2, 5) + callIndirect(table2, 6) + return callIndirect(table2, 5) + callIndirect(table2, 6) } } let res = b.callMethod(module.getExportedMethod(at: 3), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.arrayToStringForTesting(res)]) - } + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.arrayToStringForTesting(res)]) + } - testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") + testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") } func testTableInit32() throws { @@ -4192,39 +5530,58 @@ class WasmFoundationTests: XCTestCase { func wasmTableCopy(isTable64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { module in - let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(1)]} - let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} - let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} + let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(1)] + } + let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(2)] + } + let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(3)] + } // TODO(pawkra): add shared ref variant. - let table1 = module.addTable(elementType: .wasmFuncRef(), + let table1 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, - definedEntries: (0..<4).map { WasmTableType.IndexInTableAndWasmSignature.init(indexInTable: $0, signature: [] => [.wasmi64]) }, + definedEntries: (0..<4).map { + WasmTableType.IndexInTableAndWasmSignature.init( + indexInTable: $0, signature: [] => [.wasmi64]) + }, definedEntryValues: [f3, f3, f1, f2], isTable64: isTable64) module.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in - let const = { (i: Int) in isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i))} - f.wasmTableCopy(dstTable: table1, srcTable: table2, dstOffset: const(1), srcOffset: const(2), count: const(2)) + let const = { (i: Int) in + isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i)) + } + f.wasmTableCopy( + dstTable: table1, srcTable: table2, dstOffset: const(1), + srcOffset: const(2), count: const(2)) let callIndirect = { (table: Variable, idx: Int) in let idxVar = isTable64 ? f.consti64(Int64(idx)) : f.consti32(Int32(idx)) - return f.wasmCallIndirect(signature: [] => [.wasmi64], table: table, functionArgs: [], tableIndex: idxVar) + return f.wasmCallIndirect( + signature: [] => [.wasmi64], table: table, functionArgs: [], + tableIndex: idxVar) } return callIndirect(table1, 1) + callIndirect(table1, 2) } } let res = b.callMethod(module.getExportedMethod(at: 3), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.arrayToStringForTesting(res)]) - } + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.arrayToStringForTesting(res)]) + } - testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") + testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") } func testTableCopy32() throws { @@ -4245,27 +5602,35 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) - let arrayOfArrays = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: false), mutability: true, indexType: arrayi32) + let arrayOfArrays = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: false), mutability: true, + indexType: arrayi32) return [arrayi32, arrayOfArrays] } let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let array = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [ - function.consti32(42), - function.consti32(43), - function.consti32(44), - ]) - let arrayOfArrays = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [array]) - let innerArray = function.wasmArrayGet(array: arrayOfArrays, index: function.consti32(0)) - function.wasmArraySet(array: innerArray, index: function.consti32(1), element: function.consti32(100)) + let array = function.wasmArrayNewFixed( + arrayType: typeGroup[0], + elements: [ + function.consti32(42), + function.consti32(43), + function.consti32(44), + ]) + let arrayOfArrays = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [array]) + let innerArray = function.wasmArrayGet( + array: arrayOfArrays, index: function.consti32(0)) + function.wasmArraySet( + array: innerArray, index: function.consti32(1), element: function.consti32(100)) return [function.wasmArrayGet(array: innerArray, index: function.consti32(1))] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4287,17 +5652,24 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for type in typeGroup { - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { function, label, args in - let array = function.wasmArrayNewFixed(arrayType: type, elements: [ - function.consti32(-100), - function.consti32(0), - ]) - function.wasmArraySet(array: array, index: function.consti32(1), - element: function.consti32(42)) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { + function, label, args in + let array = function.wasmArrayNewFixed( + arrayType: type, + elements: [ + function.consti32(-100), + function.consti32(0), + ]) + function.wasmArraySet( + array: array, index: function.consti32(1), + element: function.consti32(42)) return [ - function.wasmArrayGet(array: array, index: function.consti32(0), isSigned: true), - function.wasmArrayGet(array: array, index: function.consti32(0), isSigned: false), - function.wasmArrayGet(array: array, index: function.consti32(1), isSigned: true), + function.wasmArrayGet( + array: array, index: function.consti32(0), isSigned: true), + function.wasmArrayGet( + array: array, index: function.consti32(0), isSigned: false), + function.wasmArrayGet( + array: array, index: function.consti32(1), isSigned: true), ] } } @@ -4329,11 +5701,15 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let array1 = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: function.consti32(3)) - let array2 = function.wasmArrayNewDefault(arrayType: typeGroup[1], size: function.consti32(2)) + let array1 = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: function.consti32(3)) + let array2 = function.wasmArrayNewDefault( + arrayType: typeGroup[1], size: function.consti32(2)) let sum = function.wasmi32BinOp( function.wasmArrayGet(array: array1, index: function.consti32(0)), - function.truncatef64Toi32(function.wasmArrayGet(array: array2, index: function.consti32(1)), isSigned: true), + function.truncatef64Toi32( + function.wasmArrayGet(array: array2, index: function.consti32(1)), + isSigned: true), binOpKind: .Add) return [sum] } @@ -4341,7 +5717,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4361,8 +5738,10 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arraySize3 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(3)) - let arraySize7 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(7)) + let arraySize3 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(3)) + let arraySize7 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(7)) let result = function.wasmi32BinOp( function.wasmArrayLen(arraySize3), function.wasmArrayLen(arraySize7), @@ -4373,7 +5752,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4388,8 +5768,14 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let types = b.wasmDefineTypeGroup { - let structOfi32 = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], indexTypes: []) - let structOfStruct = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [structOfi32]) + let structOfi32 = b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + let structOfStruct = b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field( + type: .wasmRef(.Index(), nullability: true), mutability: true) + ], indexTypes: [structOfi32]) return [structOfi32, structOfStruct] } let structOfi32 = types[0] @@ -4401,15 +5787,18 @@ class WasmGCTests: XCTestCase { function.wasmStructSet(theStruct: innerStruct, fieldIndex: 0, value: args[0]) let outerStruct = function.wasmStructNewDefault(structType: structOfStruct) function.wasmStructSet(theStruct: outerStruct, fieldIndex: 0, value: innerStruct) - let retrievedInnerStruct = function.wasmStructGet(theStruct: outerStruct, fieldIndex: 0) - let retrievedValue = function.wasmStructGet(theStruct: retrievedInnerStruct, fieldIndex: 0) + let retrievedInnerStruct = function.wasmStructGet( + theStruct: outerStruct, fieldIndex: 0) + let retrievedValue = function.wasmStructGet( + theStruct: retrievedInnerStruct, fieldIndex: 0) return [retrievedValue] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4424,8 +5813,14 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let types = b.wasmDefineTypeGroup { - let structOfi32 = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], indexTypes: []) - let structOfStruct = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [structOfi32]) + let structOfi32 = b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + let structOfStruct = b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field( + type: .wasmRef(.Index(), nullability: true), mutability: true) + ], indexTypes: [structOfi32]) return [structOfi32, structOfStruct] } let structOfi32 = types[0] @@ -4434,16 +5829,20 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in let innerStruct = function.wasmStructNew(structType: structOfi32, fields: [args[0]]) - let outerStruct = function.wasmStructNew(structType: structOfStruct, fields: [innerStruct]) - let retrievedInnerStruct = function.wasmStructGet(theStruct: outerStruct, fieldIndex: 0) - let retrievedValue = function.wasmStructGet(theStruct: retrievedInnerStruct, fieldIndex: 0) + let outerStruct = function.wasmStructNew( + structType: structOfStruct, fields: [innerStruct]) + let retrievedInnerStruct = function.wasmStructGet( + theStruct: outerStruct, fieldIndex: 0) + let retrievedValue = function.wasmStructGet( + theStruct: retrievedInnerStruct, fieldIndex: 0) return [retrievedValue] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let program = b.finalize() @@ -4458,19 +5857,26 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let structType = b.wasmDefineTypeGroup { - return [b.wasmDefineStructType(fields: [ - WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), - WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), - WasmStructTypeDescription.Field(type: .wasmPackedI16, mutability: true), - ], indexTypes: [])] + return [ + b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), + WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), + WasmStructTypeDescription.Field(type: .wasmPackedI16, mutability: true), + ], indexTypes: []) + ] }[0] let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [] => Array(repeating: .wasmi32, count: 6)) { function, label, args in + wasmModule.addWasmFunction(with: [] => Array(repeating: .wasmi32, count: 6)) { + function, label, args in let structObj = function.wasmStructNewDefault(structType: structType) - function.wasmStructSet(theStruct: structObj, fieldIndex: 0, value: function.consti32(-100)) - function.wasmStructSet(theStruct: structObj, fieldIndex: 1, value: function.consti32(42)) - function.wasmStructSet(theStruct: structObj, fieldIndex: 2, value: function.consti32(-10_000)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 0, value: function.consti32(-100)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 1, value: function.consti32(42)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 2, value: function.consti32(-10_000)) return [ function.wasmStructGet(theStruct: structObj, fieldIndex: 0, isSigned: true), function.wasmStructGet(theStruct: structObj, fieldIndex: 0, isSigned: false), @@ -4489,7 +5895,8 @@ class WasmGCTests: XCTestCase { let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) - testForOutput(program: jsProg, runner: runner, outputString: "-100,156,42,42,-10000,55536\n") + testForOutput( + program: jsProg, runner: runner, outputString: "-100,156,42,42,-10000,55536\n") } func testSignature() throws { @@ -4499,8 +5906,9 @@ class WasmGCTests: XCTestCase { let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) let selfRef = b.wasmDefineForwardOrSelfReference() let signature = b.wasmDefineSignatureType( - signature: [.wasmRef(.Index(), nullability: true), .wasmi32] => - [.wasmi32, .wasmRef(.Index(), nullability: true)], + signature: [.wasmRef(.Index(), nullability: true), .wasmi32] => [ + .wasmi32, .wasmRef(.Index(), nullability: true), + ], indexTypes: [arrayi32, selfRef]) return [arrayi32, signature] } @@ -4535,7 +5943,7 @@ class WasmGCTests: XCTestCase { let arrayType = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) let signature = b.wasmDefineSignatureType( signature: [.wasmRef(.Index(), nullability: true)] - => [.wasmRef(.Index(), nullability: true)], + => [.wasmRef(.Index(), nullability: true)], indexTypes: [arrayType, arrayType]) return [arrayType, signature] } @@ -4545,13 +5953,16 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let index = function.consti32(0) - let array = function.wasmArrayNewFixed(arrayType: arrayType, + let array = function.wasmArrayNewFixed( + arrayType: arrayType, elements: [function.consti32(1)]) - let arrayResult = function.wasmBuildLoop(with: loopSignature, args: [array]) { loopLabel, args in + let arrayResult = function.wasmBuildLoop(with: loopSignature, args: [array]) { + loopLabel, args in let val = function.wasmArrayGet(array: args[0], index: index) let newVal = function.wasmi32BinOp(val, val, binOpKind: .Add) function.wasmArraySet(array: args[0], index: index, element: newVal) - let cond = function.wasmi32CompareOp(newVal, function.consti32(50), using: .Lt_s) + let cond = function.wasmi32CompareOp( + newVal, function.consti32(50), using: .Lt_s) function.wasmBranchIf(cond, to: loopLabel, args: [args[0]]) return args }[0] @@ -4572,25 +5983,30 @@ class WasmGCTests: XCTestCase { let runner = try GetJavaScriptExecutorOrSkipTest() let jsProg = buildAndLiftProgram { b in - let structType = b.wasmDefineTypeGroup {[ - b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], - indexTypes: []) - ]}[0] + let structType = b.wasmDefineTypeGroup { + [ + b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + ] + }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let structVal = function.wasmStructNewDefault(structType: structType) - function.wasmStructSet(theStruct: structVal, fieldIndex: 0, value: function.consti32(1)) + function.wasmStructSet( + theStruct: structVal, fieldIndex: 0, value: function.consti32(1)) let signature = [b.type(of: structVal)] => [.wasmi32] // This loop creates a new struct on each iteration just for having different // values on the loop entry and the loop backedge (`br_if`). - return function.wasmBuildLoop(with: signature, args: [structVal]) { loopLabel, args in + return function.wasmBuildLoop(with: signature, args: [structVal]) { + loopLabel, args in let val = function.wasmStructGet(theStruct: args[0], fieldIndex: 0) let newVal = function.wasmi32BinOp(val, val, binOpKind: .Add) let newStruct = function.wasmStructNewDefault(structType: structType) function.wasmStructSet(theStruct: newStruct, fieldIndex: 0, value: newVal) - let cond = function.wasmi32CompareOp(newVal, function.consti32(50), using: .Lt_s) + let cond = function.wasmi32CompareOp( + newVal, function.consti32(50), using: .Lt_s) function.wasmBranchIf(cond, to: loopLabel, args: [newStruct]) return [newVal] } @@ -4614,27 +6030,31 @@ class WasmGCTests: XCTestCase { let arrayType = b.wasmDefineTypeGroup { let selfReference = b.wasmDefineForwardOrSelfReference() - let arrayOfSelf = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: selfReference) + let arrayOfSelf = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: selfReference) return [arrayOfSelf] }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in // We can arbitrarily nest these self-referencing arrays. - let array1 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(12)) + let array1 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(12)) let array2 = function.wasmArrayNewFixed(arrayType: arrayType, elements: [array1]) let array3 = function.wasmArrayNewFixed(arrayType: arrayType, elements: [array2]) let zero = function.consti32(0) let innerArray = function.wasmArrayGet( - array: function.wasmArrayGet(array: array3, index: zero), - index: zero) + array: function.wasmArrayGet(array: array3, index: zero), + index: zero) return [function.wasmArrayLen(innerArray)] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4650,7 +6070,9 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let forwardReference = b.wasmDefineForwardOrSelfReference() - let arrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: forwardReference) + let arrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: forwardReference) let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) b.wasmResolveForwardReference(forwardReference, to: arrayi32) return [arrayOfArrayi32, arrayi32] @@ -4658,19 +6080,22 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [function.consti32(42)]) - let arrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [arrayi32]) + let arrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [function.consti32(42)]) + let arrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[0], elements: [arrayi32]) let zero = function.consti32(0) let result = function.wasmArrayGet( - array: function.wasmArrayGet(array: arrayOfArrayi32, index: zero), - index: zero) + array: function.wasmArrayGet(array: arrayOfArrayi32, index: zero), + index: zero) return [result] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4686,29 +6111,39 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let forwardReference = b.wasmDefineForwardOrSelfReference() - let arrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) b.wasmResolveForwardReference(forwardReference, to: arrayi32) - let arrayOfArrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arrayOfArrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) b.wasmResolveForwardReference(forwardReference, to: arrayOfArrayi32) // Here the forward reference acts as a self reference as we don't resolve it again. - let arraySelf = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arraySelf = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) return [arrayOfArrayi32, arrayi32, arrayOfArrayOfArrayi32, arraySelf] } let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [function.consti32(42)]) - let arrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [arrayi32]) - let arrayOfArrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[2], elements: [arrayOfArrayi32]) + let arrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [function.consti32(42)]) + let arrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[0], elements: [arrayi32]) + let arrayOfArrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[2], elements: [arrayOfArrayi32]) let zero = function.consti32(0) let result = function.wasmArrayGet( - array: function.wasmArrayGet(array: function.wasmArrayGet( - array: arrayOfArrayOfArrayi32, - index: zero), + array: function.wasmArrayGet( + array: function.wasmArrayGet( + array: arrayOfArrayOfArrayi32, index: zero), - index: zero) + index: zero), + index: zero) return [result] } @@ -4716,19 +6151,23 @@ class WasmGCTests: XCTestCase { // that we produce valid Wasm (which means that the type group above was generated as // desired.) wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let arraySelf = function.wasmArrayNewFixed(arrayType: typeGroup[3], elements: [ - function.wasmRefNull(typeDef: typeGroup[3]) - ]) + let arraySelf = function.wasmArrayNewFixed( + arrayType: typeGroup[3], + elements: [ + function.wasmRefNull(typeDef: typeGroup[3]) + ]) // We can also store the arraySelf as an element into iself as the forwardReference // got reset to a selfReference after the wasmResolveForwardReference() operation. - function.wasmArraySet(array: arraySelf, index: function.consti32(0), element: arraySelf) + function.wasmArraySet( + array: arraySelf, index: function.consti32(0), element: arraySelf) return [] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4746,7 +6185,9 @@ class WasmGCTests: XCTestCase { return [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] } let typeGroupB = b.wasmDefineTypeGroup { - let typeWithDependency = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: typeGroupA[0]) + let typeWithDependency = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: typeGroupA[0]) let arrayi64 = b.wasmDefineArrayType(elementType: .wasmi64, mutability: true) return [arrayi64, typeWithDependency] } @@ -4755,7 +6196,8 @@ class WasmGCTests: XCTestCase { // typeGroupA, it still needs to import both typegroups. let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let arrayi64 = function.wasmArrayNewFixed(arrayType: typeGroupB[0], elements: [function.consti64(42)]) + let arrayi64 = function.wasmArrayNewFixed( + arrayType: typeGroupB[0], elements: [function.consti64(42)]) let result = function.wasmArrayGet(array: arrayi64, index: function.consti32(0)) return [result] } @@ -4777,7 +6219,9 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {[b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)]}[0] + let arrayType = b.wasmDefineTypeGroup { + [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] + }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in @@ -4803,13 +6247,16 @@ class WasmGCTests: XCTestCase { } func refNullAbstractTypes(sharedRef: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let unsupportedHeapType: Set = sharedRef ? [.WasmFunc, .WasmNoFunc, .WasmExn, .WasmNoExn] : [] - let supportedHeapTypes = Array(Set(WasmAbstractHeapType.allCases).subtracting(unsupportedHeapType)) + let unsupportedHeapType: Set = + sharedRef ? [.WasmFunc, .WasmNoFunc, .WasmExn, .WasmNoExn] : [] + let supportedHeapTypes = Array( + Set(WasmAbstractHeapType.allCases).subtracting(unsupportedHeapType)) let module = b.buildWasmModule { wasmModule in for heapType in supportedHeapTypes { @@ -4829,8 +6276,9 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let exportedFctCount = supportedHeapTypes.count - + supportedHeapTypes.count {$0.isUsableInJS()} + let exportedFctCount = + supportedHeapTypes.count + + supportedHeapTypes.count { $0.isUsableInJS() } for i in 0.. [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmEqRef(), .wasmEqRef()] => [.wasmi32]) { + function, label, args in return [function.wasmRefEq(args[0], args[1])] } wasmModule.addWasmFunction(with: [] => [.wasmEqRef()]) { function, label, args in @@ -4879,7 +6330,7 @@ class WasmGCTests: XCTestCase { b.callMethod(wasmRefEq, on: exports, withArgs: [b.loadInt(1), b.loadInt(1)]), b.callMethod(wasmRefEq, on: exports, withArgs: [b.loadInt(0), b.loadInt(1)]), b.callMethod(wasmRefEq, on: exports, withArgs: [array, array]), - b.callMethod(wasmRefEq, on: exports, withArgs: [array, otherArray]) + b.callMethod(wasmRefEq, on: exports, withArgs: [array, otherArray]), ] for input in cases { b.callFunction(outputFunc, withArgs: [input]) } @@ -4890,7 +6341,8 @@ class WasmGCTests: XCTestCase { } func i31Ref(shared: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -4900,28 +6352,36 @@ class WasmGCTests: XCTestCase { wasmModule.addWasmFunction(with: [.wasmi32] => [i31RefT]) { function, label, args in [function.wasmRefI31(args[0], shared: shared)] } - wasmModule.addWasmFunction(with: [i31RefT] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true), - function.wasmI31Get(args[0], isSigned: false)] + wasmModule.addWasmFunction(with: [i31RefT] => [.wasmi32, .wasmi32]) { + function, label, args in + [ + function.wasmI31Get(args[0], isSigned: true), + function.wasmI31Get(args[0], isSigned: false), + ] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let positiveI31 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) - let negativeI31 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-42)]) + let positiveI31 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let negativeI31 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-42)]) // An i31ref converts to a JS number. b.callFunction(outputFunc, withArgs: [positiveI31]) b.callFunction(outputFunc, withArgs: [negativeI31]) - let positiveResults = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [positiveI31]) - let negativeResults = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [negativeI31]) + let positiveResults = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [positiveI31]) + let negativeResults = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [negativeI31]) b.callFunction(outputFunc, withArgs: [b.arrayToStringForTesting(positiveResults)]) b.callFunction(outputFunc, withArgs: [b.arrayToStringForTesting(negativeResults)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) - testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") + testForOutput( + program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } func testi31RefShared() throws { @@ -4939,7 +6399,8 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern()]) { + function, label, args in // As ref.i31 produces a non null `ref i31`, the result of extern.convert_any is a // non-nullable `ref extern`. let result = function.wasmExternConvertAny(function.wasmRefI31(args[0])) @@ -4947,20 +6408,23 @@ class WasmGCTests: XCTestCase { return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmRefAny()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmRefAny()]) { + function, label, args in let result = function.wasmAnyConvertExtern(args[0]) XCTAssertEqual(b.type(of: result), .wasmRefAny()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in - let result = function.wasmExternConvertAny(function.wasmRefNull(type: .wasmNullRef())) + let result = function.wasmExternConvertAny( + function.wasmRefNull(type: .wasmNullRef())) XCTAssertEqual(b.type(of: result), .wasmExternRef()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmAnyRef()]) { function, label, args in - let result = function.wasmAnyConvertExtern(function.wasmRefNull(type: .wasmNullExternRef())) + let result = function.wasmAnyConvertExtern( + function.wasmRefNull(type: .wasmNullExternRef())) XCTAssertEqual(b.type(of: result), .wasmAnyRef()) return [result] } @@ -4969,7 +6433,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") for i in 0..<4 { - let result = b.callMethod(module.getExportedMethod(at: i), on: exports, withArgs: [b.loadInt(42)]) + let result = b.callMethod( + module.getExportedMethod(at: i), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [result]) } @@ -4984,7 +6449,9 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {b.wasmDefineArrayType(elementType: .wasmi32, mutability: false)}[0] + let arrayType = b.wasmDefineTypeGroup { + b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) + }[0] let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in @@ -4999,10 +6466,14 @@ class WasmGCTests: XCTestCase { function.wasmRefTest(array, refType: refNullType, typeDef: arrayType), function.wasmRefTest(null, refType: refNullType, typeDef: arrayType), ] - let result = results.reduce(function.consti32(0), { acc, r in - let shifted = function.wasmi32BinOp(acc, function.consti32(10), binOpKind: WasmIntegerBinaryOpKind.Mul) - return function.wasmi32BinOp(shifted, r, binOpKind: WasmIntegerBinaryOpKind.Add) - }) + let result = results.reduce( + function.consti32(0), + { acc, r in + let shifted = function.wasmi32BinOp( + acc, function.consti32(10), binOpKind: WasmIntegerBinaryOpKind.Mul) + return function.wasmi32BinOp( + shifted, r, binOpKind: WasmIntegerBinaryOpKind.Add) + }) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in @@ -5016,13 +6487,18 @@ class WasmGCTests: XCTestCase { let result = function.wasmRefTest(ref, refType: refType, typeDef: arrayType) return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmi32]) { + function, label, args in let result = function.wasmRefTest(args[0], refType: .wasmNullExternRef()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [catchLabel], catches: [.AllRef]) { _, _ in + let exnref = function.wasmBuildBlockWithResults( + with: [] => [.wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [catchLabel], catches: [.AllRef] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(42)]) return [] } @@ -5051,18 +6527,23 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {b.wasmDefineArrayType(elementType: .wasmi32, mutability: false)}[0] + let arrayType = b.wasmDefineTypeGroup { + b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) + }[0] let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmArrayRef()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmArrayRef()]) { + function, label, args in let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: [args[0]]) return [array] } - wasmModule.addWasmFunction(with: [.wasmEqRef()] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmEqRef()] => [.wasmi32]) { + function, label, args in let (refType, nonNullRefType, abstractRefType) = ( ILType.wasmRef(.Index(), nullability: true), ILType.wasmRef(.Index(), nullability: false), - ILType.wasmRef(.Abstract(HeapTypeInfo(.WasmArray, shared: false)), nullability: true), + ILType.wasmRef( + .Abstract(HeapTypeInfo(.WasmArray, shared: false)), nullability: true), ) let arrays = [ function.wasmRefCast(args[0], refType: refType, typeDef: arrayType), @@ -5071,9 +6552,12 @@ class WasmGCTests: XCTestCase { ] let value1 = function.wasmArrayGet(array: arrays[0], index: function.consti32(0)) let value2 = function.wasmArrayGet(array: arrays[1], index: function.consti32(0)) - return [function.wasmi32BinOp(value1, value2, binOpKind: WasmIntegerBinaryOpKind.Add)] + return [ + function.wasmi32BinOp(value1, value2, binOpKind: WasmIntegerBinaryOpKind.Add) + ] } - wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmRefExtern()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmRefExtern()]) { + function, label, args in let cast = function.wasmRefCast(args[0], refType: .wasmRefExtern()) return [cast] } @@ -5081,10 +6565,13 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let arrayRef = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(21)]) - let result = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [arrayRef]) + let arrayRef = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(21)]) + let result = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [arrayRef]) b.callFunction(outputFunc, withArgs: [result]) - let ext = b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: [b.loadInt(5)]) + let ext = b.callMethod( + module.getExportedMethod(at: 2), on: exports, withArgs: [b.loadInt(5)]) b.callFunction(outputFunc, withArgs: [ext]) let prog = b.finalize() @@ -5094,11 +6581,12 @@ class WasmGCTests: XCTestCase { func testRefCastError() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram{ b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmFuncRef()]) { function, label, args in let funcref = function.wasmRefNull(type: ILType.wasmFuncRef()) - let nullFuncType = ILType.wasmRef(.Abstract(HeapTypeInfo.init(.WasmFunc, shared: false)), nullability: false) + let nullFuncType = ILType.wasmRef( + .Abstract(HeapTypeInfo.init(.WasmFunc, shared: false)), nullability: false) let cast = function.wasmRefCast(funcref, refType: nullFuncType) return [cast] } @@ -5131,7 +6619,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmIntegerBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { + function, label, args in [function.wasmi64BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5227,7 +6716,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmIntegerBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5323,7 +6813,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmFloatBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmf64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmf64]) { + function, label, args in [function.wasmf64BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5335,7 +6826,8 @@ class WasmNumericalTests: XCTestCase { let divFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Div.rawValue)) let minFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Min.rawValue)) let maxFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Max.rawValue)) - let copysignFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) + let copysignFunc = module.getExportedMethod( + at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -5387,7 +6879,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmFloatBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmf32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmf32]) { + function, label, args in [function.wasmf32BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5399,7 +6892,8 @@ class WasmNumericalTests: XCTestCase { let divFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Div.rawValue)) let minFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Min.rawValue)) let maxFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Max.rawValue)) - let copysignFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) + let copysignFunc = module.getExportedMethod( + at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -5452,7 +6946,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmIntegerUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { + function, label, args in [function.wasmi64UnOp(args[0], unOpKind: unOp)] } } @@ -5499,7 +6994,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmIntegerUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32UnOp(args[0], unOpKind: unOp)] } } @@ -5547,7 +7043,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmFloatUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64] => [.wasmf64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64] => [.wasmf64]) { + function, label, args in [function.wasmf64UnOp(args[0], unOpKind: unOp)] } } @@ -5610,7 +7107,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmFloatUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32] => [.wasmf32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32] => [.wasmf32]) { + function, label, args in [function.wasmf32UnOp(args[0], unOpKind: unOp)] } } @@ -5674,7 +7172,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmIntegerCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi32]) { + function, label, args in [function.wasmi64CompareOp(args[0], args[1], using: compOp)] } } @@ -5765,7 +7264,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmIntegerCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32CompareOp(args[0], args[1], using: compOp)] } } @@ -5857,7 +7357,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmFloatCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmi32]) { + function, label, args in [function.wasmf64CompareOp(args[0], args[1], using: compOp)] } } @@ -5916,7 +7417,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmFloatCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmi32]) { + function, label, args in [function.wasmf32CompareOp(args[0], args[1], using: compOp)] } } @@ -6342,8 +7844,8 @@ class WasmNumericalTests: XCTestCase { ExpectEq(f32Asi32Func, [b.loadFloat(1.2)], "1067030938") ExpectEq(f64Asi64Func, [b.loadFloat(1.2)], "4608083138725491507") - ExpectEq(i32Asf32Func, [b.loadInt(1067030938)], "1.2000000476837158") - ExpectEq(i64Asf64Func, [b.loadBigInt(4608083138725491507)], "1.2") + ExpectEq(i32Asf32Func, [b.loadInt(1_067_030_938)], "1.2000000476837158") + ExpectEq(i64Asf64Func, [b.loadBigInt(4_608_083_138_725_491_507)], "1.2") let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -6387,7 +7889,7 @@ class WasmNumericalTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") var outputString = "" - let ExpectEq = { (function: String, arguments: [Variable], output: String)in + let ExpectEq = { (function: String, arguments: [Variable], output: String) in let result = b.callMethod(function, on: exports, withArgs: arguments) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: result)]) outputString += output + "\n" @@ -6405,8 +7907,8 @@ class WasmNumericalTests: XCTestCase { ExpectEq(signExtend16Intoi64Func, [b.loadBigInt(0xfffe)], "-2") ExpectEq(signExtend16Intoi64Func, [b.loadBigInt(0xff0001)], "1") - ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xfffffffe)], "-2") - ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xff00000001)], "1") + ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xffff_fffe)], "-2") + ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xff_0000_0001)], "1") let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -6538,7 +8040,8 @@ class WasmSpliceTests: XCTestCase { b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) // +1 for the wasm-gc signature type that is created implicitly. splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) @@ -6583,7 +8086,8 @@ class WasmSpliceTests: XCTestCase { b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) // +1 for the wasm-gc signature type that is created implicitly. splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) @@ -6615,7 +8119,8 @@ class WasmSpliceTests: XCTestCase { module.addWasmFunction(with: [] => []) { function, _, _ in let _ = function.constf64(42.42) let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) return [] } @@ -6630,7 +8135,8 @@ class WasmSpliceTests: XCTestCase { class WasmJSPITests: XCTestCase { func testJSPI() throws { // We need to have the right arguments here and we need a shell that supports jspi. - let runner = try GetJavaScriptExecutorOrSkipTest(type: .user, withArguments: ["--wasm-staging", "--expose-gc"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .user, withArguments: ["--wasm-staging", "--expose-gc"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -6642,7 +8148,9 @@ class WasmJSPITests: XCTestCase { let function = b.buildAsyncFunction(with: .parameters(n: 1)) { args in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) let json = b.createNamedVariable(forBuiltin: "JSON") - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("stringify", on: json, withArgs: [args[0]])]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("stringify", on: json, withArgs: [args[0]])]) b.doReturn(b.loadInt(1)) } @@ -6653,7 +8161,11 @@ class WasmJSPITests: XCTestCase { // Now lets build the module let module = b.buildWasmModule { m in m.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32]) { f, label, args in - [f.wasmJsCall(function: importFunction, withArgs: args, withWasmSignature: [.wasmExternRef()] => [.wasmi32])!] + [ + f.wasmJsCall( + function: importFunction, withArgs: args, + withWasmSignature: [.wasmExternRef()] => [.wasmi32])! + ] } } @@ -6692,7 +8204,11 @@ class WasmJSPITests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobali64: Variable = b.createWasmGlobal(value: .wasmi64(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: wasmGlobali64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) let module = b.buildWasmModule { wasmModule in // Function 0, modifies the imported global. From 1d3e779b4732a62b50725e785ceb25b5e2deb7cd Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 16:44:34 +0200 Subject: [PATCH 026/223] [format] Add formatting check to presubmit.py Bug: 430616180 Change-Id: I6784d3f4232e11b272cbb7a345713edff05c7426 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9156216 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Tools/presubmit.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) mode change 100644 => 100755 Tools/presubmit.py diff --git a/Tools/presubmit.py b/Tools/presubmit.py old mode 100644 new mode 100755 index 7c6efa58e..f9502c874 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -1,3 +1,19 @@ +#!/usr/bin/env python3 + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import os import shutil import subprocess @@ -13,7 +29,7 @@ "ast.proto" ] -def check_git_clean(): +def check_git_clean(info): """Check that the git repository does not have any uncommitted changes.""" result = subprocess.run( ["git", "diff", "--name-only"], @@ -23,7 +39,7 @@ def check_git_clean(): output = result.stdout.decode().strip() if output != "": diff_result = subprocess.run(["git", "diff"], cwd=BASE_DIR, capture_output=True, check=True) - assert False, f"Unexpected modified files: {output}\n== Diff ==\n{diff_result.stdout.decode()}" + assert False, f"Unexpected modified files {info}: {output}\n== Diff ==\n{diff_result.stdout.decode()}" def check_proto(): """Check that program.proto is up-to-date.""" @@ -31,7 +47,7 @@ def check_proto(): proto_dir = BASE_DIR / "Sources/Fuzzilli/Protobuf" subprocess.run(["python3", "./gen_programproto.py"], cwd=proto_dir, check=True) # gen_programproto.py should be a no-op. - check_git_clean() + check_git_clean("after running gen_programproto.py") if not shutil.which("protoc"): print("Skipping protobuf validation as protoc is not available.") @@ -48,12 +64,16 @@ def check_proto(): cmd = ["protoc", "--swift_opt=Visibility=Public", "--swift_out=."] + KNOWN_PROTO_FILES subprocess.run(cmd, cwd=proto_dir, check=True, env=env) # Regenerating the protobuf files should be a no-op. - check_git_clean() + check_git_clean("after regenerating protobuf files") + +def check_formatting(): + subprocess.run(["swift", "format", BASE_DIR, "--recursive", "--parallel", "--in-place"], check=True) + check_git_clean("after auto-formatting") def main(): - check_git_clean() + check_git_clean("before any checks") check_proto() - # TODO(mliedtke): Ensure formatting delta is zero once we enable automated formatting. + check_formatting() if __name__ == '__main__': From cbade79edaf1dae0c233890b7957f560008d2c63 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 8 Apr 2026 12:04:39 +0000 Subject: [PATCH 027/223] Add default parameters to generated functions This CL adds support for default parameters in generated functions. Methods with default parameters, and JS to FuzzIL compilation code will be added later. Change-Id: I5b3583a8656c72a4068c497677bd6f18c98badb8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9176497 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 81 +++++++++++++++---- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 55 +++++++++---- Sources/Fuzzilli/FuzzIL/Instruction.swift | 5 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 32 ++++++-- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 9 ++- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 49 ++++++++--- Sources/Fuzzilli/Protobuf/operations.pb.swift | 9 ++- Sources/Fuzzilli/Protobuf/operations.proto | 1 + Tests/FuzzilliTests/LifterTest.swift | 74 +++++++++++++++++ 9 files changed, 264 insertions(+), 51 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 631f5a3f9..c6c701d4c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3324,11 +3324,46 @@ public class ProgramBuilder { return parameters.count } - public static func parameters(n: Int, hasRestParameter: Bool = false) - -> SubroutineDescriptor - { + public static func parameters( + n: Int, hasRestParameter: Bool = false, defaultParameterIndices: [Int] = [] + ) -> SubroutineDescriptor { return SubroutineDescriptor( - withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) + withParameters: Parameters( + count: n, hasRestParameter: hasRestParameter, + defaultParameterIndices: defaultParameterIndices)) + } + + /// Returns a copy of this SubroutineDescriptor but with some parameters turned into default parameters. + public func withRandomDefaultParameters( + probability chance: Double, randomVariable: () -> Variable + ) + -> (SubroutineDescriptor, [Variable]) + { + var defaultParameterIndices = [Int]() + var defaultValues = [Variable]() + if self.parameters.count > 0 { + for i in 0.. SubroutineDescriptor { @@ -3364,11 +3399,13 @@ public class ProgramBuilder { @discardableResult public func buildPlainFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndPlainFunction()) return instr.output @@ -3376,10 +3413,13 @@ public class ProgramBuilder { @discardableResult public func buildArrowFunction( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) + let instr = emit( + BeginArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndArrowFunction()) return instr.output @@ -3388,11 +3428,13 @@ public class ProgramBuilder { @discardableResult public func buildGeneratorFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndGeneratorFunction()) return instr.output @@ -3401,11 +3443,13 @@ public class ProgramBuilder { @discardableResult public func buildAsyncFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncFunction()) return instr.output @@ -3413,10 +3457,13 @@ public class ProgramBuilder { @discardableResult public func buildAsyncArrowFunction( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) + let instr = emit( + BeginAsyncArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncArrowFunction()) return instr.output @@ -3425,12 +3472,14 @@ public class ProgramBuilder { @discardableResult public func buildAsyncGeneratorFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( BeginAsyncGeneratorFunction( - parameters: descriptor.parameters, functionName: functionName)) + parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncGeneratorFunction()) return instr.output diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index f759f51ff..93fd51a6f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1504,11 +1504,15 @@ public let CodeGenerators: [CodeGenerator] = [ [ GeneratorStub("PlainFunctionBeginGenerator", provides: [.javascript, .subroutine]) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1532,11 +1536,15 @@ public let CodeGenerators: [CodeGenerator] = [ { b in // We could consider having a standalone DirectiveGenerator, but probably most of the time it won't do anything meaningful. // We could also consider keeping a list of known directives in the JavaScriptEnvironment, but currently we only use 'use strict'. - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1561,11 +1569,15 @@ public let CodeGenerators: [CodeGenerator] = [ "ArrowFunctionBeginGenerator", provides: [.subroutine, .javascript] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginArrowFunction(parameters: randomParameters.parameters)) + BeginArrowFunction(parameters: randomParameters.parameters), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1586,12 +1598,16 @@ public let CodeGenerators: [CodeGenerator] = [ "GeneratorFunctionBeginGenerator", provides: [.generatorFunction, .subroutine, .javascript] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) + parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1623,11 +1639,15 @@ public let CodeGenerators: [CodeGenerator] = [ GeneratorStub( "AsyncFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1653,12 +1673,15 @@ public let CodeGenerators: [CodeGenerator] = [ "AsyncArrowFunctionBeginGenerator", provides: [.javascript, .asyncFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginAsyncArrowFunction( - parameters: randomParameters.parameters)) + parameters: randomParameters.parameters), withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1689,12 +1712,16 @@ public let CodeGenerators: [CodeGenerator] = [ "AsyncGeneratorFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction, .generatorFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginAsyncGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) + parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index e40947e3b..8ccfd989e 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -329,6 +329,7 @@ extension Instruction: ProtobufConvertible { return Fuzzilli_Protobuf_Parameters.with { $0.count = UInt32(parameters.count) $0.hasRest_p = parameters.hasRestParameter + $0.defaultParameterIndices = parameters.defaultParameterIndices.map(UInt32.init) } } @@ -1754,7 +1755,9 @@ extension Instruction: ProtobufConvertible { } func convertParameters(_ parameters: Fuzzilli_Protobuf_Parameters) -> Parameters { - return Parameters(count: Int(parameters.count), hasRestParameter: parameters.hasRest_p) + return Parameters( + count: Int(parameters.count), hasRestParameter: parameters.hasRest_p, + defaultParameterIndices: parameters.defaultParameterIndices.map(Int.init)) } // Converts to the Wasm world global type diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 958602acf..8daeb1073 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1320,15 +1320,32 @@ public struct Parameters { private let numParameters: UInt32 /// Whether the last parameter is a rest parameter. let hasRestParameter: Bool + /// Indices of parameters that have a default value. + /// The n-th default parameter will be the n-th input to the BeginAnySubroutine instruction. + let defaultParameterIndices: [Int] /// The total number of parameters. This is equivalent to the number of inner outputs produced from the parameters. var count: Int { return Int(numParameters) } - init(count: Int, hasRestParameter: Bool = false) { + var numDefaultParameters: Int { + return defaultParameterIndices.count + } + + init(count: Int, hasRestParameter: Bool = false, defaultParameterIndices: [Int] = []) { + assert( + !hasRestParameter || !defaultParameterIndices.contains(count - 1), + "Rest parameter cannot have a default value") + assert( + defaultParameterIndices.allSatisfy({ $0 >= 0 && $0 < count }), + "Invalid default parameter index") + assert( + defaultParameterIndices == defaultParameterIndices.sorted(), + "Default parameter indices must be sorted") self.numParameters = UInt32(count) self.hasRestParameter = hasRestParameter + self.defaultParameterIndices = defaultParameterIndices } } @@ -1339,16 +1356,17 @@ class BeginAnySubroutine: JsOperation { let parameters: Parameters init( - parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, - attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, - contextOpened: Context + parameters: Parameters, numInputs: Int? = nil, numOutputs: Int = 0, + numInnerOutputs: Int = 0, attributes: Operation.Attributes = .isBlockStart, + requiredContext: Context = .javascript, contextOpened: Context ) { assert(contextOpened.contains(.subroutine)) assert(attributes.contains(.isBlockStart)) self.parameters = parameters super.init( - numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, - attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + numInputs: numInputs ?? parameters.numDefaultParameters, numOutputs: numOutputs, + numInnerOutputs: numInnerOutputs, attributes: attributes, + requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -1365,7 +1383,7 @@ class BeginAnyFunction: BeginAnySubroutine { init(parameters: Parameters, contextOpened: Context = [.javascript, .subroutine]) { super.init( parameters: parameters, - numInputs: 0, + numInputs: parameters.numDefaultParameters, numOutputs: 1, numInnerOutputs: parameters.count, contextOpened: contextOpened) diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 4dffd0123..a62659c93 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -408,7 +408,14 @@ public class FuzzILLifter: Lifter { .beginAsyncArrowFunction(let op as BeginAnyFunction), .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("\(output()) <- \(op.name) -> \(params)") + let inputs = + instr.inputs.isEmpty + ? "" + : " [" + + zip(op.parameters.defaultParameterIndices, instr.inputs).map { + "\($0): \(lift($1))" + }.joined(separator: ", ") + "]" + w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() case .endPlainFunction(let op as EndAnyFunction), diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 8f12d3f0e..b9a546761 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -833,32 +833,36 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .beginPlainFunction: - liftFunctionDefinitionBegin(instr, keyword: "function", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "function", withInputs: inputs, using: &w) case .beginArrowFunction(let op): guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } liftArrowFunctionDefinitionBegin( - instr, parameters: op.parameters, isAsync: false, using: &w, + instr, withInputs: inputs, parameters: op.parameters, isAsync: false, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginGeneratorFunction: - liftFunctionDefinitionBegin(instr, keyword: "function*", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "function*", withInputs: inputs, using: &w) case .beginAsyncFunction: - liftFunctionDefinitionBegin(instr, keyword: "async function", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "async function", withInputs: inputs, using: &w) case .beginAsyncArrowFunction(let op): guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } liftArrowFunctionDefinitionBegin( - instr, parameters: op.parameters, isAsync: true, using: &w, + instr, withInputs: inputs, parameters: op.parameters, isAsync: true, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginAsyncGeneratorFunction: - liftFunctionDefinitionBegin(instr, keyword: "async function*", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "async function*", withInputs: inputs, using: &w) case .endArrowFunction(_), .endAsyncArrowFunction: @@ -1934,12 +1938,21 @@ public class JavaScriptLifter: Lifter { return (isGuarded ? "?." : "") + "[" + safeName + "]" } - private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { + private func liftParameters( + _ parameters: Parameters, as variables: [String], defaultValues: [String?] = [] + ) -> String { assert(parameters.count == variables.count) + let actualDefaultValues = + defaultValues.isEmpty + ? [String?](repeating: nil, count: parameters.count) : defaultValues + assert(actualDefaultValues.count == parameters.count) var paramList = [String]() - for v in variables { + for (v, defaultValue) in zip(variables, actualDefaultValues) { if parameters.hasRestParameter && v == variables.last { + assert(defaultValue == nil) paramList.append("..." + v) + } else if let defaultValue { + paramList.append(v + " = " + defaultValue) } else { paramList.append(v) } @@ -1948,7 +1961,8 @@ public class JavaScriptLifter: Lifter { } private func liftFunctionDefinitionBegin( - _ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter + _ instr: Instruction, keyword FUNCTION: String, withInputs inputs: [Expression], + using w: inout JavaScriptWriter ) { // Function are lifted as `function f3(a4, a5, a6) { ...`. // This will produce functions with a recognizable .name property, which the JavaScriptExploreLifting code makes use of (see shouldTreatAsConstructor). @@ -1963,13 +1977,20 @@ public class JavaScriptLifter: Lifter { } let NAME = w.declare(instr.output, as: functionName) let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("\(FUNCTION) \(NAME)(\(PARAMS)) {") w.enterNewBlock() } private func liftArrowFunctionDefinitionBegin( _ instr: Instruction, + withInputs inputs: [Expression], parameters: Parameters, isAsync: Bool, using w: inout JavaScriptWriter, @@ -1984,7 +2005,13 @@ public class JavaScriptLifter: Lifter { ) let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let params = liftParameters(parameters, as: vars) + + var defaultValues = [String?](repeating: nil, count: parameters.count) + for (inputIdx, paramIdx) in parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + + let params = liftParameters(parameters, as: vars, defaultValues: defaultValues) functionLiftingStack.push( FunctionLiftingState( diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 03dc972b5..322a6fe2e 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1606,6 +1606,8 @@ public struct Fuzzilli_Protobuf_Parameters: Sendable { public var hasRest_p: Bool = false + public var defaultParameterIndices: [UInt32] = [] + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -6101,7 +6103,7 @@ extension Fuzzilli_Protobuf_WasmAtomicCmpxchgType: SwiftProtobuf._ProtoNameProvi extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Parameters" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}count\0\u{1}hasRest\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}count\0\u{1}hasRest\0\u{1}defaultParameterIndices\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -6111,6 +6113,7 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me switch fieldNumber { case 1: try { try decoder.decodeSingularUInt32Field(value: &self.count) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRest_p) }() + case 3: try { try decoder.decodeRepeatedUInt32Field(value: &self.defaultParameterIndices) }() default: break } } @@ -6123,12 +6126,16 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me if self.hasRest_p != false { try visitor.visitSingularBoolField(value: self.hasRest_p, fieldNumber: 2) } + if !self.defaultParameterIndices.isEmpty { + try visitor.visitPackedUInt32Field(value: self.defaultParameterIndices, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_Parameters, rhs: Fuzzilli_Protobuf_Parameters) -> Bool { if lhs.count != rhs.count {return false} if lhs.hasRest_p != rhs.hasRest_p {return false} + if lhs.defaultParameterIndices != rhs.defaultParameterIndices {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 9cfb20633..c48160805 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -19,6 +19,7 @@ package fuzzilli.protobuf; message Parameters { uint32 count = 1; bool hasRest = 2; + repeated uint32 defaultParameterIndices = 3; } message LoadInteger { diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 0840baf24..faf67c326 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -4356,4 +4356,78 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testPlainFunctionDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + let v1 = b.loadString("default") + + // function f(a, b = 42, c = "default") { return a; } + b.buildPlainFunction( + with: .parameters(n: 3, defaultParameterIndices: [1, 2]), defaultValues: [v0, v1] + ) { args in + b.doReturn(args[0]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function f2(a3, a4 = 42, a5 = "default") { + return a3; + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // (a, b = 42) => { return a; } + b.buildArrowFunction( + with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[0]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = "(a2, a3 = 42) => a2;\n" + + XCTAssertEqual(actual, expected) + } + + func testPlainFunctionMixedDefaultParametersLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // function f(a = 42, b) { return b; } + b.buildPlainFunction( + with: .parameters(n: 2, defaultParameterIndices: [0]), defaultValues: [v0] + ) { args in + b.doReturn(args[1]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function f1(a2 = 42, a3) { + return a3; + } + + """ + + XCTAssertEqual(actual, expected) + } } From 4c88bcd50d37f9a752e701641175441826f51ac5 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 8 Apr 2026 15:00:39 +0000 Subject: [PATCH 028/223] Add JS-to-FuzzIL transpilation for default params This CL adds JS to FuzzIL transpilation support for default parameters in the context of functions. Change-Id: If3451444a6ef0ce032825039a92acbef340438ed Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182176 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Compiler/Compiler.swift | 28 +- Sources/Fuzzilli/Compiler/Parser/parser.js | 7 +- Sources/Fuzzilli/Protobuf/ast.pb.swift | 294 +++++++++++++----- Sources/Fuzzilli/Protobuf/ast.proto | 1 + .../function_with_default_parameters.js | 42 +++ 5 files changed, 292 insertions(+), 80 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 079d8673a..91b7dab1e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -366,6 +366,7 @@ public class JavaScriptCompiler { } case .functionDeclaration(let functionDeclaration): + let defaultValues = try compileDefaultValues(for: functionDeclaration.parameters) let parameters = convertParameters(functionDeclaration.parameters) let functionBegin: Operation let functionEnd: Operation @@ -390,7 +391,7 @@ public class JavaScriptCompiler { throw CompilerError.invalidNodeError("invalid function declaration type \(type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) // The function may have been accessed before it was defined due to function hoisting, so // here we may overwrite an existing variable mapping. mapOrRemap(functionDeclaration.name, to: instr.output) @@ -1064,6 +1065,7 @@ public class JavaScriptCompiler { } case .functionExpression(let functionExpression): + let defaultValues = try compileDefaultValues(for: functionExpression.parameters) let parameters = convertParameters(functionExpression.parameters) let functionBegin: Operation let functionEnd: Operation @@ -1086,7 +1088,7 @@ public class JavaScriptCompiler { throw CompilerError.invalidNodeError("invalid function declaration type \(type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) try enterNewScope { mapParameters(functionExpression.parameters, to: instr.innerOutputs) for statement in functionExpression.body { @@ -1098,6 +1100,7 @@ public class JavaScriptCompiler { return instr.output case .arrowFunctionExpression(let arrowFunction): + let defaultValues = try compileDefaultValues(for: arrowFunction.parameters) let parameters = convertParameters(arrowFunction.parameters) let functionBegin: Operation let functionEnd: Operation @@ -1113,7 +1116,7 @@ public class JavaScriptCompiler { "invalid arrow function type \(arrowFunction.type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) try enterNewScope { mapParameters(arrowFunction.parameters, to: instr.innerOutputs) guard let body = arrowFunction.body else { @@ -1482,9 +1485,26 @@ public class JavaScriptCompiler { } } + private func compileDefaultValues(for parameters: Compiler_Protobuf_Parameters) throws + -> [Variable] + { + var defaultValues = [Variable]() + for param in parameters.parameters { + if param.hasDefaultValue { + defaultValues.append(try compileExpression(param.defaultValue)) + } + } + return defaultValues + } + private func convertParameters(_ parameters: Compiler_Protobuf_Parameters) -> Parameters { + let defaultParameterIndices = parameters.parameters.enumerated() + .filter { $0.element.hasDefaultValue } + .map { $0.offset } + return Parameters( - count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) + count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p, + defaultParameterIndices: defaultParameterIndices) } /// Convenience accessor for the currently active scope. diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index aa06d05ce..c1cba8b76 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -83,11 +83,16 @@ function parse(script, proto) { return Statement.create(statement); } - // TODO(bettscheider): Add support for default parameters. function visitParameter(param) { switch (param.type) { case 'Identifier': return make('Parameter', { name: param.name }); + case 'AssignmentPattern': + assert(param.left.type === 'Identifier', "Expected identifier in assignment pattern"); + return make('Parameter', { + name: param.left.name, + defaultValue: visitExpression(param.right) + }); case 'RestElement': return make('Parameter', { name: param.argument.name }); default: diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index c556a80e6..365d0c7bd 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -163,16 +163,30 @@ public struct Compiler_Protobuf_AST: Sendable { } /// A parameter in a function declaration. Not an expression on its own. -public struct Compiler_Protobuf_Parameter: Sendable { +public struct Compiler_Protobuf_Parameter: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var name: String { + get {_storage._name} + set {_uniqueStorage()._name = newValue} + } + + public var defaultValue: Compiler_Protobuf_Expression { + get {_storage._defaultValue ?? Compiler_Protobuf_Expression()} + set {_uniqueStorage()._defaultValue = newValue} + } + /// Returns true if `defaultValue` has been explicitly set. + public var hasDefaultValue: Bool {_storage._defaultValue != nil} + /// Clears the value of `defaultValue`. Subsequent reads from it will return its default value. + public mutating func clearDefaultValue() {_uniqueStorage()._defaultValue = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_EmptyStatement: Sendable { @@ -964,28 +978,31 @@ public struct Compiler_Protobuf_ContinueStatement: Sendable { public init() {} } -public struct Compiler_Protobuf_CatchClause: Sendable { +public struct Compiler_Protobuf_CatchClause: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// The parameter is optional public var parameter: Compiler_Protobuf_Parameter { - get {_parameter ?? Compiler_Protobuf_Parameter()} - set {_parameter = newValue} + get {_storage._parameter ?? Compiler_Protobuf_Parameter()} + set {_uniqueStorage()._parameter = newValue} } /// Returns true if `parameter` has been explicitly set. - public var hasParameter: Bool {self._parameter != nil} + public var hasParameter: Bool {_storage._parameter != nil} /// Clears the value of `parameter`. Subsequent reads from it will return its default value. - public mutating func clearParameter() {self._parameter = nil} + public mutating func clearParameter() {_uniqueStorage()._parameter = nil} - public var body: [Compiler_Protobuf_Statement] = [] + public var body: [Compiler_Protobuf_Statement] { + get {_storage._body} + set {_uniqueStorage()._body = newValue} + } public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_FinallyClause: Sendable { @@ -1000,39 +1017,41 @@ public struct Compiler_Protobuf_FinallyClause: Sendable { public init() {} } -public struct Compiler_Protobuf_TryStatement: Sendable { +public struct Compiler_Protobuf_TryStatement: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var body: [Compiler_Protobuf_Statement] = [] + public var body: [Compiler_Protobuf_Statement] { + get {_storage._body} + set {_uniqueStorage()._body = newValue} + } /// The catch clause is optional public var `catch`: Compiler_Protobuf_CatchClause { - get {_catch ?? Compiler_Protobuf_CatchClause()} - set {_catch = newValue} + get {_storage._catch ?? Compiler_Protobuf_CatchClause()} + set {_uniqueStorage()._catch = newValue} } /// Returns true if ``catch`` has been explicitly set. - public var hasCatch: Bool {self._catch != nil} + public var hasCatch: Bool {_storage._catch != nil} /// Clears the value of ``catch``. Subsequent reads from it will return its default value. - public mutating func clearCatch() {self._catch = nil} + public mutating func clearCatch() {_uniqueStorage()._catch = nil} /// The finally clause is optional public var finally: Compiler_Protobuf_FinallyClause { - get {_finally ?? Compiler_Protobuf_FinallyClause()} - set {_finally = newValue} + get {_storage._finally ?? Compiler_Protobuf_FinallyClause()} + set {_uniqueStorage()._finally = newValue} } /// Returns true if `finally` has been explicitly set. - public var hasFinally: Bool {self._finally != nil} + public var hasFinally: Bool {_storage._finally != nil} /// Clears the value of `finally`. Subsequent reads from it will return its default value. - public mutating func clearFinally() {self._finally = nil} + public mutating func clearFinally() {_uniqueStorage()._finally = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _catch: Compiler_Protobuf_CatchClause? = nil - fileprivate var _finally: Compiler_Protobuf_FinallyClause? = nil + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_ThrowStatement: @unchecked Sendable { @@ -2501,29 +2520,76 @@ extension Compiler_Protobuf_AST: SwiftProtobuf.Message, SwiftProtobuf._MessageIm extension Compiler_Protobuf_Parameter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Parameter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}defaultValue\0") + + fileprivate class _StorageClass { + var _name: String = String() + var _defaultValue: Compiler_Protobuf_Expression? = nil + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _name = source._name + _defaultValue = source._defaultValue + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &_storage._name) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._defaultValue) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if !_storage._name.isEmpty { + try visitor.visitSingularStringField(value: _storage._name, fieldNumber: 1) + } + try { if let v = _storage._defaultValue { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_Parameter, rhs: Compiler_Protobuf_Parameter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._name != rhs_storage._name {return false} + if _storage._defaultValue != rhs_storage._defaultValue {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4183,36 +4249,74 @@ extension Compiler_Protobuf_CatchClause: SwiftProtobuf.Message, SwiftProtobuf._M public static let protoMessageName: String = _protobuf_package + ".CatchClause" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameter\0\u{1}body\0") + fileprivate class _StorageClass { + var _parameter: Compiler_Protobuf_Parameter? = nil + var _body: [Compiler_Protobuf_Statement] = [] + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _parameter = source._parameter + _body = source._body + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._parameter) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._body) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._parameter { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 2) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._parameter { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + if !_storage._body.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._body, fieldNumber: 2) + } } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_CatchClause, rhs: Compiler_Protobuf_CatchClause) -> Bool { - if lhs._parameter != rhs._parameter {return false} - if lhs.body != rhs.body {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._parameter != rhs_storage._parameter {return false} + if _storage._body != rhs_storage._body {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4252,41 +4356,81 @@ extension Compiler_Protobuf_TryStatement: SwiftProtobuf.Message, SwiftProtobuf._ public static let protoMessageName: String = _protobuf_package + ".TryStatement" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}body\0\u{1}catch\0\u{1}finally\0") + fileprivate class _StorageClass { + var _body: [Compiler_Protobuf_Statement] = [] + var _catch: Compiler_Protobuf_CatchClause? = nil + var _finally: Compiler_Protobuf_FinallyClause? = nil + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _body = source._body + _catch = source._catch + _finally = source._finally + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._catch) }() - case 3: try { try decoder.decodeSingularMessageField(value: &self._finally) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &_storage._body) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._catch) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._finally) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 1) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if !_storage._body.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._body, fieldNumber: 1) + } + try { if let v = _storage._catch { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._finally { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() } - try { if let v = self._catch { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - try { if let v = self._finally { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_TryStatement, rhs: Compiler_Protobuf_TryStatement) -> Bool { - if lhs.body != rhs.body {return false} - if lhs._catch != rhs._catch {return false} - if lhs._finally != rhs._finally {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._body != rhs_storage._body {return false} + if _storage._catch != rhs_storage._catch {return false} + if _storage._finally != rhs_storage._finally {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index d53216273..b9ce69147 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -23,6 +23,7 @@ message AST { // A parameter in a function declaration. Not an expression on its own. message Parameter { string name = 1; + Expression defaultValue = 2; } message EmptyStatement { diff --git a/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js b/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js new file mode 100644 index 000000000..5c634769e --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js @@ -0,0 +1,42 @@ +if (typeof output === 'undefined') output = console.log; + +// plain function +function f(v1, v2=42) { + return v1+v2; +} + +output(f(42)); +output(f(42,43)); + +// arrow function +const arrow = (v1, v2=10) => v1 + v2; +output(arrow(5)); +output(arrow(5, 15)); + + +// function expr +const expr = function(v1, v2="default") { + return v1 + v2; +}; +output(expr("hello ")); +output(expr("hello ", "world")); + + +// generator function +function* gen(v1, v2=1) { + yield v1; + yield v2; +} +for (let v of gen(100)) { + output(v); +} +for (let v of gen(100, 200)) { + output(v); +} + +// async function +async function asyncF(v1, v2=Promise.resolve(42)) { + return v1 + await v2; +} +asyncF(10).then(output); +asyncF(10, Promise.resolve(20)).then(output); From d13654f129ec9fac25d49dec051ce7b8b960a3f5 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 8 Apr 2026 22:55:08 +0200 Subject: [PATCH 029/223] [v8] Sometimes disable generic Wasm wrappers Change-Id: Id5d47cf3d566fbcd1d9e671220d9cdcc930b201a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182836 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 59ec66b44..8919b7511 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -1012,6 +1012,11 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--wasm-inlining-ignore-call-counts") } + // Force compiled Wasm wrappers. + if probability(0.3) { + args.append("--no-wasm-generic-wrapper") + } + // // Future features that should sometimes be enabled. // From 7a578ff6e5899bb776689413b02410875aca84ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 9 Apr 2026 11:17:38 +0200 Subject: [PATCH 030/223] Fix compiler warning Change-Id: I8d4b9ee4f0648091b06262a0cbee6a65b311db92 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184556 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index c6c701d4c..55dcae720 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2422,7 +2422,7 @@ public class ProgramBuilder { // Check if we can produce it with findOrGenerateWasmVar let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) } - if findVariable { requirement.fulfilled(by: self.type(of: $0)) } == nil { + if findVariable(satisfying: { requirement.fulfilled(by: self.type(of: $0)) }) == nil { // Check for other CodeGenerators that can produce the given type in this context. let usableGenerators = fuzzer.codeGenerators.filter { From 5ad6837e008eaf334510f28a839d302b4b942399 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Thu, 9 Apr 2026 14:09:20 +0000 Subject: [PATCH 031/223] Add default params to generated methods + ctors This CL adds support for default parameters in generated methods and constructors. JS to FuzzIL compilation code will be added in a subsequent CL. Change-Id: Idc8ba4b53be0373f5090e7b8f78db583e3eab0dd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184576 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 67 ++++++--- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 54 +++++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 6 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 43 ++++-- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 42 +++++- Tests/FuzzilliTests/LifterTest.swift | 142 ++++++++++++++++++ 6 files changed, 295 insertions(+), 59 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 55dcae720..5c363ae05 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2754,22 +2754,27 @@ public class ProgramBuilder { } public func addMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( - BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) + BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralMethod()) } public func addComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralComputedMethod()) } @@ -2868,10 +2873,13 @@ public class ProgramBuilder { } public func addConstructor( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassConstructor(parameters: descriptor.parameters)) + let instr = b.emit( + BeginClassConstructor(parameters: descriptor.parameters), withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassConstructor()) } @@ -2898,23 +2906,28 @@ public class ProgramBuilder { } public func addInstanceMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassMethod( - methodName: name, parameters: descriptor.parameters, isStatic: false)) + methodName: name, parameters: descriptor.parameters, isStatic: false), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } public func addInstanceComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } @@ -2977,23 +2990,28 @@ public class ProgramBuilder { } public func addStaticMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassMethod( - methodName: name, parameters: descriptor.parameters, isStatic: true)) + methodName: name, parameters: descriptor.parameters, isStatic: true), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } public func addStaticComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } @@ -3036,12 +3054,15 @@ public class ProgramBuilder { } public func addPrivateInstanceMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassPrivateMethod( - methodName: name, parameters: descriptor.parameters, isStatic: false)) + methodName: name, parameters: descriptor.parameters, isStatic: false), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } @@ -3054,12 +3075,15 @@ public class ProgramBuilder { } public func addPrivateStaticMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassPrivateMethod( - methodName: name, parameters: descriptor.parameters, isStatic: true)) + methodName: name, parameters: descriptor.parameters, isStatic: true), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } @@ -3487,10 +3511,13 @@ public class ProgramBuilder { @discardableResult public func buildConstructor( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginConstructor(parameters: descriptor.parameters)) + let instr = emit( + BeginConstructor(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndConstructor()) return instr.output diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 93fd51a6f..cdc4863d0 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -551,7 +551,11 @@ public let CodeGenerators: [CodeGenerator] = [ Int.random(in: 1...maxProperties))) // Define a constructor function... - let c = b.buildConstructor(with: b.randomParameters()) { args in + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) + let c = b.buildConstructor(with: randomParameters, defaultValues: defaultValues) { args in let this = args[0] // We don't want |this| to be used as property value, so hide it. @@ -809,13 +813,17 @@ public let CodeGenerators: [CodeGenerator] = [ b.randomCustomMethodName, notIn: b.currentObjectLiteral.methods) - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) b.emit( BeginObjectLiteralMethod( methodName: methodName, - parameters: randomParameters.parameters)) + parameters: randomParameters.parameters), + withInputs: defaultValues) }, GeneratorStub( "ObjectLiteralMethodEndGenerator", @@ -836,12 +844,15 @@ public let CodeGenerators: [CodeGenerator] = [ // Try to find a computed method name that hasn't already been added to this literal. let methodName = b.randomJsVariable( notIn: b.currentObjectLiteral.computedMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginObjectLiteralComputedMethod( parameters: parameters.parameters), - withInputs: [methodName]) + withInputs: [methodName] + defaultValues) }, GeneratorStub( "ObjectLiteralComputedMethodEndGenerator", @@ -954,21 +965,25 @@ public let CodeGenerators: [CodeGenerator] = [ return } - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let args = b.emit( BeginClassConstructor( - parameters: randomParameters.parameters) + parameters: randomParameters.parameters), + withInputs: defaultValues ).innerOutputs if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: args.last!) } - let this = args[0] + let this = args.first! // Derived classes must call `super()` before accessing this, but non-derived classes must not call `super()`. if b.currentClassDefinition.isDerivedClass { b.hide(this) // We need to hide |this| so it isn't used as argument for `super()` @@ -1039,13 +1054,17 @@ public let CodeGenerators: [CodeGenerator] = [ b.randomCustomMethodName, notIn: b.currentClassDefinition.instanceMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassMethod( methodName: methodName, parameters: parameters.parameters, - isStatic: false)) + isStatic: false), + withInputs: defaultValues) }, GeneratorStub( "ClassInstanceMethodEndGenerator", @@ -1067,13 +1086,16 @@ public let CodeGenerators: [CodeGenerator] = [ // Try to find a method that hasn't already been added to this class. let methodName = b.randomJsVariable( notIn: b.currentClassDefinition.instanceComputedMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassComputedMethod( parameters: parameters.parameters, isStatic: false), - withInputs: [methodName]) + withInputs: [methodName] + defaultValues) }, GeneratorStub( "ClassInstanceComputedMethodEndGenerator", @@ -1197,14 +1219,18 @@ public let CodeGenerators: [CodeGenerator] = [ let methodName = b.generateString( b.randomCustomMethodName, notIn: b.currentClassDefinition.staticMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassMethod( methodName: methodName, parameters: parameters.parameters, - isStatic: true)) + isStatic: true), + withInputs: defaultValues) }, GeneratorStub( diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 8daeb1073..d02651787 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -605,7 +605,8 @@ final class BeginObjectLiteralComputedMethod: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter super.init( - parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + parameters: parameters, numInputs: 1 + parameters.numDefaultParameters, + numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) } @@ -854,7 +855,8 @@ final class BeginClassComputedMethod: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init( - parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + parameters: parameters, numInputs: 1 + parameters.numDefaultParameters, + numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index a62659c93..2cc5d9465 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -36,6 +36,16 @@ public class FuzzILLifter: Lifter { return lift(instr.innerOutput) } + func liftDefaultParameters(_ parameters: Parameters, _ defaultValues: ArraySlice) + -> String + { + guard !defaultValues.isEmpty else { return "" } + let defaults = zip(parameters.defaultParameterIndices, defaultValues).map { + "\($0): \(lift($1))" + }.joined(separator: ", ") + return " [\(defaults)]" + } + switch instr.op.opcode { case .loadInteger(let op): w.emit("\(output()) <- LoadInteger '\(op.value)'") @@ -114,16 +124,18 @@ public class FuzzILLifter: Lifter { case .beginObjectLiteralMethod(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginObjectLiteralMethod `\(op.methodName)` -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginObjectLiteralMethod `\(op.methodName)`\(inputs) -> \(params)") w.increaseIndentionLevel() case .endObjectLiteralMethod: w.decreaseIndentionLevel() w.emit("EndObjectLiteralMethod") - case .beginObjectLiteralComputedMethod: + case .beginObjectLiteralComputedMethod(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginObjectLiteralComputedMethod \(input(0)) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs.dropFirst()) + w.emit("BeginObjectLiteralComputedMethod \(input(0))\(inputs) -> \(params)") w.increaseIndentionLevel() case .endObjectLiteralComputedMethod: @@ -182,9 +194,10 @@ public class FuzzILLifter: Lifter { w.emit(line) w.increaseIndentionLevel() - case .beginClassConstructor: + case .beginClassConstructor(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassConstructor -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassConstructor\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassConstructor: @@ -218,7 +231,8 @@ public class FuzzILLifter: Lifter { case .beginClassMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)' -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassMethod: @@ -228,7 +242,8 @@ public class FuzzILLifter: Lifter { case .beginClassComputedMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0)) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs.dropFirst()) + w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0))\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassComputedMethod: @@ -294,7 +309,8 @@ public class FuzzILLifter: Lifter { case .beginClassPrivateMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)' -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassPrivateMethod: @@ -408,13 +424,7 @@ public class FuzzILLifter: Lifter { .beginAsyncArrowFunction(let op as BeginAnyFunction), .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - let inputs = - instr.inputs.isEmpty - ? "" - : " [" - + zip(op.parameters.defaultParameterIndices, instr.inputs).map { - "\($0): \(lift($1))" - }.joined(separator: ", ") + "]" + let inputs = liftDefaultParameters(op.parameters, instr.inputs) w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() @@ -429,7 +439,8 @@ public class FuzzILLifter: Lifter { case .beginConstructor(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("\(output()) <- \(op.name) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() case .endConstructor(let op): diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index b9a546761..6a733fac2 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -424,7 +424,11 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = quoteIdentifierIfNeeded(op.methodName) currentObjectLiteral.beginMethod("\(METHOD)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -434,7 +438,11 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[1 + inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = input(0) currentObjectLiteral.beginMethod("[\(METHOD)](\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -519,7 +527,11 @@ public class JavaScriptLifter: Lifter { case .beginClassConstructor(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("constructor(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) @@ -569,7 +581,11 @@ public class JavaScriptLifter: Lifter { case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = quoteIdentifierIfNeeded(op.methodName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") @@ -578,7 +594,11 @@ public class JavaScriptLifter: Lifter { case .beginClassComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[1 + inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = input(0) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)[\(METHOD)](\(PARAMS)) {") @@ -639,7 +659,11 @@ public class JavaScriptLifter: Lifter { case .beginClassPrivateMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = op.methodName let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)#\(METHOD)(\(PARAMS)) {") @@ -910,7 +934,11 @@ public class JavaScriptLifter: Lifter { let NAME = "F\(instr.output.number)" w.declare(instr.output, as: NAME) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("function \(NAME)(\(PARAMS)) {") w.enterNewBlock() // Disallow invoking constructors without `new` (i.e. Construct in FuzzIL). diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index faf67c326..9033e9283 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -4430,4 +4430,146 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testObjectLiteralMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildObjectLiteral { obj in + obj.addMethod( + "foo", with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v4 = { + foo(a2, a3 = 42) { + return a3; + }, + }; + + """ + + XCTAssertEqual(actual, expected) + } + + func testClassMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildClassDefinition { cls in + cls.addInstanceMethod( + "bar", with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C1 { + bar(a3, a4 = 42) { + return a4; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testClassConstructorDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildClassDefinition { cls in + cls.addConstructor( + with: .parameters(n: 1, defaultParameterIndices: [0]), defaultValues: [v0] + ) { args in + b.setProperty("foo", of: args[0], to: args[1]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C1 { + constructor(a3 = 42) { + this.foo = a3; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testObjectLiteralComputedMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + let v1 = b.loadString("computed") + + b.buildObjectLiteral { obj in + obj.addComputedMethod( + v1, with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v5 = { + ["computed"](a3, a4 = 42) { + return a4; + }, + }; + + """ + + XCTAssertEqual(actual, expected) + } + + func testConstructorDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // function F(a, b = 42) { if (!new.target) ... } + b.buildConstructor( + with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function F1(a3, a4 = 42) { + if (!new.target) { throw 'must be called with new'; } + } + + """ + + XCTAssertEqual(actual, expected) + } } From 58f196f4537064676084a8760dffd311ec81ad99 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 10 Apr 2026 10:00:56 +0000 Subject: [PATCH 032/223] Add JS-to-FuzzIL transpilation for default params in methods This CL adds JS to FuzzIL transpilation support for default parameters in the context of methods. Change-Id: I92b72780e1e994b86d067f3239d87507afde15f7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184577 Commit-Queue: Leon Bettscheider Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Compiler.swift | 38 +++++++--- .../methods_with_default_parameters.js | 74 +++++++++++++++++++ 2 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 91b7dab1e..188868063 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -71,9 +71,10 @@ public class JavaScriptCompiler { private func compileClass( _ name: String, superClass: ExpressionNode?, fields: [ClassFieldNode], isExpression: Bool ) throws -> Variable { - // The expressions for property values and computed properties need to be emitted before the class declaration is opened. + // The expressions for property values, computed properties and method default parameters need to be emitted before the class declaration is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() + var defaultValuesPerSubroutine = [[Variable]]() for field in fields { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in class declaration") @@ -87,12 +88,17 @@ public class JavaScriptCompiler { } key = property.key case .method(let method): + defaultValuesPerSubroutine.append(try compileDefaultValues(for: method.parameters)) key = method.key case .getter(let getter): key = getter.key case .setter(let setter): key = setter.key - case .ctor, .staticInitializer: + case .ctor(let constructor): + defaultValuesPerSubroutine.append( + try compileDefaultValues(for: constructor.parameters)) + key = nil + case .staticInitializer: key = nil } @@ -104,6 +110,7 @@ public class JavaScriptCompiler { // Reverse the arrays since we'll remove the elements in FIFO order. propertyValues.reverse() computedKeys.reverse() + defaultValuesPerSubroutine.reverse() let classDecl: Instruction if let superClass = superClass { @@ -146,8 +153,10 @@ public class JavaScriptCompiler { emit(op, withInputs: inputs) case .ctor(let constructor): + let defaultValues = defaultValuesPerSubroutine.removeLast() let parameters = convertParameters(constructor.parameters) - let head = emit(BeginClassConstructor(parameters: parameters)) + let head = emit( + BeginClassConstructor(parameters: parameters), withInputs: defaultValues) try enterNewScope { var parameters = head.innerOutputs @@ -161,6 +170,7 @@ public class JavaScriptCompiler { emit(EndClassConstructor()) case .method(let method): + let defaultValues = defaultValuesPerSubroutine.removeLast() let parameters = convertParameters(method.parameters) let head: Instruction @@ -171,16 +181,18 @@ public class JavaScriptCompiler { case .name(let name): head = emit( BeginClassMethod( - methodName: name, parameters: parameters, isStatic: method.isStatic)) + methodName: name, parameters: parameters, isStatic: method.isStatic), + withInputs: defaultValues) case .index(let index): head = emit( BeginClassMethod( methodName: String(index), parameters: parameters, - isStatic: method.isStatic)) + isStatic: method.isStatic), + withInputs: defaultValues) case .expression: head = emit( BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), - withInputs: [computedKeys.removeLast()]) + withInputs: [computedKeys.removeLast()] + defaultValues) } try enterNewScope { @@ -886,9 +898,10 @@ public class JavaScriptCompiler { return rhs case .objectExpression(let objectExpression): - // The expressions for property values and computed properties need to be emitted before the object literal is opened. + // The expressions for property values, computed properties and method default parameters need to be emitted before the object literal is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() + var methodDefaultValues = [[Variable]]() for field in objectExpression.fields { guard let field = field.field else { throw CompilerError.invalidNodeError( @@ -901,6 +914,7 @@ public class JavaScriptCompiler { propertyValues.append(try compileExpression(property.value)) key = property.key case .method(let method): + methodDefaultValues.append(try compileDefaultValues(for: method.parameters)) key = method.key case .getter(let getter): key = getter.key @@ -915,6 +929,7 @@ public class JavaScriptCompiler { // Reverse the arrays since we'll remove the elements in FIFO order. propertyValues.reverse() computedKeys.reverse() + methodDefaultValues.reverse() // Now build the object literal. emit(BeginObjectLiteral()) @@ -937,6 +952,7 @@ public class JavaScriptCompiler { withInputs: [computedKeys.removeLast()] + inputs) } case .method(let method): + let defaultValues = methodDefaultValues.removeLast() let parameters = convertParameters(method.parameters) let head: Instruction @@ -947,15 +963,17 @@ public class JavaScriptCompiler { switch key { case .name(let name): head = emit( - BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + BeginObjectLiteralMethod(methodName: name, parameters: parameters), + withInputs: defaultValues) case .index(let index): head = emit( BeginObjectLiteralMethod( - methodName: String(index), parameters: parameters)) + methodName: String(index), parameters: parameters), + withInputs: defaultValues) case .expression: head = emit( BeginObjectLiteralComputedMethod(parameters: parameters), - withInputs: [computedKeys.removeLast()]) + withInputs: [computedKeys.removeLast()] + defaultValues) } try enterNewScope { diff --git a/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js b/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js new file mode 100644 index 000000000..8384dc3a7 --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js @@ -0,0 +1,74 @@ +if (typeof output === 'undefined') output = console.log; + +// Object literal method +const propName = "computedMethod"; +const obj = { + method(v1, v2 = 42) { + return v1 + v2; + }, + [propName](v1, v2 = 10) { + return v1 + v2; + } +}; + +output(obj.method(5)); +output(obj.method(5, 15)); +output(obj.computedMethod(5)); +output(obj.computedMethod(5, 15)); + +// Class constructor +class C { + constructor(v1, v2 = "default") { + this.v1 = v1; + this.v2 = v2; + } + + method(v1, v2 = 100) { + return v1 + v2; + } + + method_with_multiple_default_params_1(v1 = -1, v2 = 2, v3 = 3) { + return -1 * v1 + v2 + v3; + } + + method_with_multiple_default_params_2(v1, v2 = 2, v3 = 3) { + return -1 * v1 + v2 + v3; + } + + static staticMethod(v1, v2 = 200) { + return v1 + v2; + } + + [propName](v1, v2 = 300) { + return v1 + v2; + } + + ["computedMethodWithMultipleDefaultParams"](v1, v2 = 300, v3=400) { + return -1 * v1 + v2 + v3; + } +} + +const instance = new C("hello"); +output(instance.v1); +output(instance.v2); + +output(instance.method(5)); +output(instance.method(5, 15)); + +output(instance.method_with_multiple_default_params_1()) +output(instance.method_with_multiple_default_params_1(10)) +output(instance.method_with_multiple_default_params_2(10)) +output(instance.method_with_multiple_default_params_2(-10, 20, 30)) + +output(instance.computedMethod(5)); +output(instance.computedMethod(5, 15)); + +output(instance.computedMethodWithMultipleDefaultParams(-1)); +output(instance.computedMethodWithMultipleDefaultParams(10, 2, 3)); + +const instance2 = new C("hello", "world"); +output(instance2.v1); +output(instance2.v2); + +output(C.staticMethod(10)); +output(C.staticMethod(10, 20)); From 7ad5f6c3c15caba036d53a50d0084a52c38c4e64 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 10 Apr 2026 12:44:18 +0200 Subject: [PATCH 033/223] [tools] Add --format and --regenerate-proto to presubmit helper Change-Id: I4e0f51c795d4d262c420b28cbc059e70b4060506 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9189336 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Tools/presubmit.py | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/Tools/presubmit.py b/Tools/presubmit.py index f9502c874..cf59ac292 100755 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import argparse import os import shutil import subprocess @@ -21,6 +22,7 @@ from pathlib import Path BASE_DIR = Path(__file__).parent.parent.resolve() +PROTO_DIR = BASE_DIR / "Sources/Fuzzilli/Protobuf" KNOWN_PROTO_FILES = [ "program.proto", @@ -41,14 +43,10 @@ def check_git_clean(info): diff_result = subprocess.run(["git", "diff"], cwd=BASE_DIR, capture_output=True, check=True) assert False, f"Unexpected modified files {info}: {output}\n== Diff ==\n{diff_result.stdout.decode()}" -def check_proto(): - """Check that program.proto is up-to-date.""" - print("Checking generated protobuf files...") - proto_dir = BASE_DIR / "Sources/Fuzzilli/Protobuf" - subprocess.run(["python3", "./gen_programproto.py"], cwd=proto_dir, check=True) - # gen_programproto.py should be a no-op. - check_git_clean("after running gen_programproto.py") +def regenerate_opcodes(): + subprocess.run(["python3", "./gen_programproto.py"], cwd=PROTO_DIR, check=True) +def regenerate_proto(): if not shutil.which("protoc"): print("Skipping protobuf validation as protoc is not available.") return @@ -62,18 +60,39 @@ def check_proto(): env = os.environ.copy() env["PATH"] = f"{swift_protobuf_path}/.build/debug:" + env["PATH"] cmd = ["protoc", "--swift_opt=Visibility=Public", "--swift_out=."] + KNOWN_PROTO_FILES - subprocess.run(cmd, cwd=proto_dir, check=True, env=env) - # Regenerating the protobuf files should be a no-op. + subprocess.run(cmd, cwd=PROTO_DIR, check=True, env=env) + +def check_proto(): + """Check that program.proto is up-to-date.""" + print("Checking generated protobuf files...") + regenerate_opcodes() + check_git_clean("after running gen_programproto.py") + regenerate_proto() check_git_clean("after regenerating protobuf files") -def check_formatting(): +def run_formatting(): subprocess.run(["swift", "format", BASE_DIR, "--recursive", "--parallel", "--in-place"], check=True) + +def check_formatting(): + run_formatting() check_git_clean("after auto-formatting") def main(): - check_git_clean("before any checks") - check_proto() - check_formatting() + parser = argparse.ArgumentParser() + parser.add_argument("--format", action="store_true", help="Run auto-formatting.") + parser.add_argument("--regenerate-proto", action="store_true", help="Regenerate OpCodes.swift protobuf files.") + args = parser.parse_args() + + if args.format or args.regenerate_proto: + if args.regenerate_proto: + regenerate_opcodes() + regenerate_proto() + if args.format: + run_formatting() + else: + check_git_clean("before any checks") + check_proto() + check_formatting() if __name__ == '__main__': From 17ac8a6f7826ac6d211419647931cd848774d408 Mon Sep 17 00:00:00 2001 From: Tigran Bantikyan Date: Fri, 10 Apr 2026 13:36:03 +0000 Subject: [PATCH 034/223] Add support for integer enumerations Fuzzilli currently only has support for enumerations with string values. Being able to represent integer enumerations through the Fuzzilli type system would reduce the amount of supporting code that profile authors need to write. For instance, if a method has an argument that is of an integer enumeration type, the current approach would be to mark the argument as a `integer` in the Fuzzilli profile and write a custom CodeGenerator that constains the argument's values to those of the enumeration. The author cannot rely on CodeGenerators such as `MethodCallGenerator`, since these will overwhelmingly provide incorrect integer values for this argument. This CL introduces the `intEnumeration` type to Fuzzilli to support integer enumerations. The changes follow the example set by the existing `enumeration`. Namely, the introduction of a `customName` field for integers allows Fuzzilli to reliably distinguish regular integer variabels from intEnumeration variables. Rather than complicating the `isEnumeration` and `isEnumerationOrNamedString` properties on `ILType`, this CL also introduces an `isEnumeration` parameter to the `TypeExtension` constructor to explicitly identify enumerations. Fixed: 500001059 Change-Id: Ia5b2c632864a0b9fa7e7d4c7357f0de3e0a5e23c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182892 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 13 +++-- .../Environment/JavaScriptEnvironment.swift | 4 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 +++- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 4 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 49 ++++++++++++++----- .../Fuzzilli/Mutators/OperationMutator.swift | 11 ++++- Sources/Fuzzilli/Protobuf/operations.pb.swift | 22 ++++++++- Sources/Fuzzilli/Protobuf/operations.proto | 1 + Tests/FuzzilliTests/JSTyperTests.swift | 22 +++++++++ Tests/FuzzilliTests/TypeSystemTest.swift | 34 +++++++++++++ 11 files changed, 150 insertions(+), 25 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 5c363ae05..e3bf101f0 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -769,7 +769,10 @@ public class ProgramBuilder { // We only need to check against all base types from TypeSystem.swift, this works because we use .MayBe // TODO: Not sure how we should handle merge types, e.g. .string + .object(...). let typeGenerators: [(ILType, () -> Variable)] = [ - (.integer, { return self.loadInt(self.randomInt()) }), + ( + .integer, + { type.isEnumeration ? self.loadEnum(type) : self.loadInt(self.randomInt()) } + ), ( .string, { @@ -2643,8 +2646,8 @@ public class ProgramBuilder { } @discardableResult - public func loadInt(_ value: Int64) -> Variable { - return emit(LoadInteger(value: value)).output + public func loadInt(_ value: Int64, customName: String? = nil) -> Variable { + return emit(LoadInteger(value: value, customName: customName)).output } @discardableResult @@ -2665,6 +2668,10 @@ public class ProgramBuilder { @discardableResult public func loadEnum(_ type: ILType) -> Variable { assert(type.isEnumeration) + if type.Is(.integer) { + let value = Int64(chooseUniform(from: type.enumValues))! + return loadInt(value, customName: type.group) + } return loadString(chooseUniform(from: type.enumValues), customName: type.group) } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 05a1c753b..bb2429870 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1022,7 +1022,7 @@ public class JavaScriptEnvironment: ComponentBase { if let signatures = group.methods[propertyName] { return .unboundFunction(signatures.first, receiver: baseType) } - } else if !baseType.isEnumerationOrNamedString { + } else if !(baseType.isEnumeration || baseType.isNamedString) { // This shouldn't happen, probably forgot to register the object group. logger.warning("No type information for object group \(groupName) available") } @@ -1037,7 +1037,7 @@ public class JavaScriptEnvironment: ComponentBase { if let signatures = group.methods[methodName] { return signatures } - } else if !baseType.isEnumerationOrNamedString { + } else if !(baseType.isEnumeration || baseType.isNamedString) { // This shouldn't happen, probably forgot to register the object group logger.warning("No type information for object group \(groupName) available") } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 8ccfd989e..be087fdc3 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -561,7 +561,12 @@ extension Instruction: ProtobufConvertible { case .nop: $0.nop = Fuzzilli_Protobuf_Nop() case .loadInteger(let op): - $0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { $0.value = op.value } + $0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { + $0.value = op.value + if let customName = op.customName { + $0.customName = customName + } + } case .loadBigInt(let op): $0.loadBigInt = Fuzzilli_Protobuf_LoadBigInt.with { $0.value = op.value } case .loadFloat(let op): @@ -1959,7 +1964,8 @@ extension Instruction: ProtobufConvertible { } op = cachedOp case .loadInteger(let p): - op = LoadInteger(value: p.value) + let customName = p.customName.isEmpty ? nil : p.customName + op = LoadInteger(value: p.value, customName: customName) case .loadBigInt(let p): op = LoadBigInt(value: p.value) case .loadFloat(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 8c49dcc19..f3519b16f 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1676,8 +1676,9 @@ public struct JSTyper: Analyzer { } switch instr.op.opcode { - case .loadInteger: - set(instr.output, .integer) + case .loadInteger(let op): + // Set to enum type if en enum for `op.customName` is registered. + set(instr.output, op.customName.flatMap(environment.getEnum) ?? .integer) case .loadBigInt: set(instr.output, .bigint) diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index d02651787..be392b830 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -177,9 +177,11 @@ final class LoadInteger: JsOperation { override var opcode: Opcode { .loadInteger(self) } let value: Int64 + let customName: String? - init(value: Int64) { + init(value: Int64, customName: String? = nil) { self.value = value + self.customName = customName super.init(numOutputs: 1, attributes: [.isMutable]) } } diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index 2fc55cec3..e546fae6d 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -164,10 +164,20 @@ public struct ILType: Hashable { /// Constructs an enum type, which is a string with a limited set of allowed values. public static func enumeration(ofName name: String, withValues values: [String]) -> ILType { let ext = TypeExtension( - group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) + group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil, + isEnumeration: true) return ILType(definiteType: .string, ext: ext) } + /// Constructs an enum type, which is an integer with a limited set of allowed values. + public static func intEnumeration(ofName name: String, withValues values: [Int64]) -> ILType { + let stringValues = values.map { String($0) } + let ext = TypeExtension( + group: name, properties: Set(stringValues), methods: Set(), signature: nil, + wasmExt: nil, isEnumeration: true) + return ILType(definiteType: .integer, ext: ext) + } + /// Constructs an named string: this is a string that typically has some complex format. /// /// Most code will treat these as strings, but the JavaScriptEnvironment can register @@ -597,11 +607,11 @@ public struct ILType: Hashable { } public var isEnumeration: Bool { - return Is(.string) && ext != nil && !ext!.properties.isEmpty + return ext?.isEnumeration ?? false } - public var isEnumerationOrNamedString: Bool { - return Is(.string) && ext != nil && group != nil + public var isNamedString: Bool { + return (Is(.string) && ext != nil && group != nil) } public var group: String? { @@ -819,12 +829,14 @@ public struct ILType: Hashable { if wasmExt == nil && (self.wasmType ?? other.wasmType) != nil { group = nil } + let isEnumeration = self.isEnumeration && other.isEnumeration && group != nil return ILType( definiteType: definiteType, possibleType: possibleType, ext: TypeExtension( group: group, properties: commonProperties, methods: commonMethods, - signature: signature, wasmExt: wasmExt, receiver: receiver)) + signature: signature, wasmExt: wasmExt, receiver: receiver, + isEnumeration: isEnumeration)) } public static func | (lhs: ILType, rhs: ILType) -> ILType { @@ -924,11 +936,13 @@ public struct ILType: Hashable { wasmExt = wasmIntersection } + let isEnumeration = self.isEnumeration || other.isEnumeration + return ILType( definiteType: definiteType, possibleType: possibleType, ext: TypeExtension( group: group, properties: properties, methods: methods, signature: signature, - wasmExt: wasmExt, receiver: receiver)) + wasmExt: wasmExt, receiver: receiver, isEnumeration: isEnumeration)) } public static func & (lhs: ILType, rhs: ILType) -> ILType { @@ -1001,11 +1015,13 @@ public struct ILType: Hashable { let wasmExt = self.wasmType ?? other.wasmType + let isEnumeration = self.isEnumeration || other.isEnumeration + // We just take the self.wasmExt as they have to be the same, see `canMerge`. let ext = TypeExtension( group: group, properties: self.properties.union(other.properties), methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, - receiver: receiver) + receiver: receiver, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: ext) } @@ -1032,7 +1048,7 @@ public struct ILType: Hashable { newProperties.insert(property) let newExt = TypeExtension( group: group, properties: newProperties, methods: methods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1054,7 +1070,7 @@ public struct ILType: Hashable { newMethods.remove(name) let newExt = TypeExtension( group: group, properties: newProperties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1067,7 +1083,7 @@ public struct ILType: Hashable { newMethods.insert(method) let newExt = TypeExtension( group: group, properties: properties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1085,7 +1101,7 @@ public struct ILType: Hashable { newMethods.remove(method) let newExt = TypeExtension( group: group, properties: properties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1094,7 +1110,8 @@ public struct ILType: Hashable { return self } let newExt = TypeExtension( - group: group, properties: properties, methods: methods, signature: signature) + group: group, properties: properties, methods: methods, signature: signature, + isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1378,9 +1395,12 @@ class TypeExtension: Hashable { // The receiver type of a function (used for unbound functions). let receiver: ILType? + // Used to indentify whether a type is an enumeration + let isEnumeration: Bool + init?( group: String? = nil, properties: Set, methods: Set, signature: Signature?, - wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil + wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil, isEnumeration: Bool = false ) { if group == nil && properties.isEmpty && methods.isEmpty && signature == nil && wasmExt == nil && receiver == nil @@ -1394,6 +1414,7 @@ class TypeExtension: Hashable { self.signature = signature self.wasmExt = wasmExt self.receiver = receiver + self.isEnumeration = isEnumeration } static func == (lhs: TypeExtension, rhs: TypeExtension) -> Bool { @@ -1403,6 +1424,7 @@ class TypeExtension: Hashable { && lhs.signature == rhs.signature && lhs.wasmExt == rhs.wasmExt && lhs.receiver == rhs.receiver + && lhs.isEnumeration == rhs.isEnumeration } public func hash(into hasher: inout Hasher) { @@ -1412,6 +1434,7 @@ class TypeExtension: Hashable { hasher.combine(signature) hasher.combine(wasmExt) hasher.combine(receiver) + hasher.combine(isEnumeration) } } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index c7614ff25..1ce56d0c8 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -45,7 +45,16 @@ public class OperationMutator: BaseInstructionMutator { private func mutateOperation(_ instr: Instruction, _ b: ProgramBuilder) -> Instruction { let newOp: Operation switch instr.op.opcode { - case .loadInteger(_): + case .loadInteger(let op): + // Half the time we want to just hit the regular path + if Bool.random(), + let customName = op.customName, + let type = b.fuzzer.environment.getEnum(ofName: customName) + { + let value = Int64(chooseUniform(from: type.enumValues))! + newOp = LoadInteger(value: value, customName: customName) + break + } newOp = LoadInteger(value: b.randomInt()) case .loadBigInt(_): newOp = LoadBigInt(value: b.randomInt()) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 322a6fe2e..cc4bafbf1 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1620,9 +1620,20 @@ public struct Fuzzilli_Protobuf_LoadInteger: Sendable { public var value: Int64 = 0 + public var customName: String { + get {_customName ?? String()} + set {_customName = newValue} + } + /// Returns true if `customName` has been explicitly set. + public var hasCustomName: Bool {self._customName != nil} + /// Clears the value of `customName`. Subsequent reads from it will return its default value. + public mutating func clearCustomName() {self._customName = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _customName: String? = nil } public struct Fuzzilli_Protobuf_LoadBigInt: Sendable { @@ -6143,7 +6154,7 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_LoadInteger: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".LoadInteger" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}value\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}value\0\u{1}customName\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -6152,20 +6163,29 @@ extension Fuzzilli_Protobuf_LoadInteger: SwiftProtobuf.Message, SwiftProtobuf._M // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularInt64Field(value: &self.value) }() + case 2: try { try decoder.decodeSingularStringField(value: &self._customName) }() default: break } } } public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 if self.value != 0 { try visitor.visitSingularInt64Field(value: self.value, fieldNumber: 1) } + try { if let v = self._customName { + try visitor.visitSingularStringField(value: v, fieldNumber: 2) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_LoadInteger, rhs: Fuzzilli_Protobuf_LoadInteger) -> Bool { if lhs.value != rhs.value {return false} + if lhs._customName != rhs._customName {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index c48160805..c654f8b6f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -24,6 +24,7 @@ message Parameters { message LoadInteger { int64 value = 1; + optional string customName = 2; } message LoadBigInt { diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index e41776ea4..bfb9afd4a 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -2262,4 +2262,26 @@ class JSTyperTests: XCTestCase { XCTAssertNil(unionType.group) } + + func testIntEnumerationCustomName() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let mockIntEnum = ILType.intEnumeration(ofName: "MockIntEnum", withValues: [1337, 42]) + fuzzer.environment.registerEnumeration(mockIntEnum) + + let v1 = b.loadInt(1337, customName: "MockIntEnum") + let v2 = b.loadInt(1337) + + // v1 should be typed as the enumeration + XCTAssertEqual(b.type(of: v1).group, "MockIntEnum") + XCTAssertTrue(b.type(of: v1).isEnumeration) + XCTAssert(b.type(of: v1).Is(mockIntEnum)) + XCTAssert(b.type(of: v1).Is(.integer)) + + // v2 should be typed as a generic integer + XCTAssertNil(b.type(of: v2).group) + XCTAssertFalse(b.type(of: v2).isEnumeration) + XCTAssert(b.type(of: v2).Is(.integer)) + } } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 91f17cdb2..5833233e6 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -1548,6 +1548,40 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(receiverObject.intersection(with: receiverNil), receiverObject) } + func testEnumerationTypeOperations() { + let enumA = ILType.enumeration(ofName: "EnumA", withValues: ["A", "B"]) + let enumB = ILType.intEnumeration(ofName: "EnumB", withValues: [1, 2]) + let genericString = ILType.string + let genericInt = ILType.integer + + XCTAssertTrue(enumA.isEnumeration) + XCTAssertTrue(enumB.isEnumeration) + XCTAssertFalse(genericString.isEnumeration) + XCTAssertFalse(genericInt.isEnumeration) + + // Union: enumA | genericString should be genericString, so not an enumeration. + XCTAssertFalse((enumA | genericString).isEnumeration) + // Union: enumB | genericInt should be genericInt, so not an enumeration. + XCTAssertFalse((enumB | genericInt).isEnumeration) + // Union: enumA (string) | enumB (int) should be number | string, so not an enumeration. + XCTAssertFalse((enumA | enumB).isEnumeration) + + // Intersection: enumA & genericString should be enumA, so it should be an enumeration. + XCTAssertTrue((enumA & genericString).isEnumeration) + // Intersection: enumB & genericInt should be enumB, so it should be an enumeration. + XCTAssertTrue((enumB & genericInt).isEnumeration) + + // Intersection of string enum and int enum should be .nothing, which is not an enumeration. + XCTAssertEqual(enumA & enumB, .nothing) + XCTAssertFalse((enumA & enumB).isEnumeration) + + // Merging: enumA + object should maintain the isEnumeration flag. + let obj = ILType.object(withProperties: ["foo"]) + XCTAssertFalse(obj.isEnumeration) + XCTAssertTrue((enumA + obj).isEnumeration) + XCTAssertTrue((enumB + obj).isEnumeration) + } + let primitiveTypes: [ILType] = [ .undefined, .integer, .float, .string, .boolean, .bigint, .regexp, ] From 6b80463cff7fa2a3eed591cbbb2c502ecb2a8b32 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 8 Apr 2026 17:51:50 +0200 Subject: [PATCH 035/223] [wasm] Try to finally fix the jsTyper.getWasmTypeDef() crash This change refactors the WasmTypeGroupReducer to not just remove unused type definitions from the WasmEndTypeGroup but to also remove the type definition itself. In general, the GenericInstructionReducer should take care of that, however, with a sufficiently large program it could happen that the minimization doesn't finish within its max iteration count and it removed the input-wiring but not the type definition. The CodeGenMutator can then perform a `buildIntoTypeGroup()` and add a new struct type that uses the "unexported" type definition as an element type. Subsequently, another run of the CodeGenMutator can add a WasmStructNew operation that will then call jsTyper.getWasmTypeDef() which relies on all typess inside a type group (including the element type) being exported by the WasmEndTypeGroup operation which isn't the case here causing the fatalError. Bug: 475996631 Change-Id: I269d7c9c2069c1b31e85a17e103c87f593a241f0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9188577 Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- .../Minimization/WasmTypeGroupReducer.swift | 97 ++++++++++++------- Tests/FuzzilliTests/MinimizerTest.swift | 72 +++++++++++++- 2 files changed, 132 insertions(+), 37 deletions(-) diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 76b991b43..85f93525a 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -12,57 +12,82 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + +// The TypeGroupReducer removes unused type definition. A type definition is considered unused if it +// is not used by any other operation but the WasmEndTypeGroup and if the corresponding output +// of the WasmEndTypeGroup is not used anywhere inside the program. +// +// This reducer preserves the invariant that each type defined inside a type group is also exposed +// by the WasmEndTypeGroup operation. +// Note that a WasmResolveForwardReference(v0, v1) makes v1 used and prevents its removal by this +// reducer. However, the GenericInstructionReducer will try to remove the +// WasmResolveForwardReference, so this is not an issue. struct WasmTypeGroupReducer: Reducer { func reduce(with helper: MinimizationHelper) { - // Compute all candidates: intermediate operations in a data flow chain. - var candidates = [Int]() - var uses = VariableMap() + var useCount = VariableMap() + var definitions = VariableMap() + + // Count all usages of Wasm type definitions. for instr in helper.code { - for input in instr.inputs { - uses[input]? += 1 + if instr.op is WasmTypeOperation { + for output in instr.outputs { + useCount[output] = 0 + definitions[output] = instr.index + } } - guard instr.op is WasmTypeOperation else { continue } - // Define the usages for all WasmTypeOperation so that we also count usages of a type - // inside a type group (i.e. by other type operations). - for output in instr.outputs { - uses[output] = 0 + if instr.op is WasmEndTypeGroup { + // Propagate usage counts from the input to the output variables. Note that the + // WasmEndTypeGroup ends the scope in which the inputs are defined (meaning there) + // can't be any usages after the WasmEndTypeGroup instruction. + for (input, output) in zip(instr.inputs, instr.outputs) { + useCount[output] = useCount[input]! + } + } else { + // Any usage but the WasmEndTypeGroup should be tracked. + // (This includes WasmResolveForwardReference.) + for input in instr.inputs { + useCount[input]? += 1 + } } + } + + if definitions.isEmpty { + return + } - // For now, we only consider EndTypeGroup instructions. + // Create replacements for WasmEndTypeGroup and collect type definitions to remove. + var toRemove = IndexSet() + var endTypeGroupReplacements = [Int: Instruction]() + + for instr in helper.code { guard case .wasmEndTypeGroup = instr.op.opcode else { continue } - candidates.append(instr.index) - for (input, output) in zip(instr.inputs, instr.outputs) { - // Subtract 1 as the input in the WasmEndTypeGroup itself is not a reason to keep - // the type. However, if the type is used inside the type group, it also needs to be - // exposed by the type group. Right now the JSTyper requires that all types defined - // in a type group are exposed by their WasmEndTypeGroup instruction. - uses[output]! += uses[input]! - 1 + let keptInoutsMap = zip(instr.inputs, instr.outputs).filter { useCount[$0.1]! > 0 } + if keptInoutsMap.count == instr.inputs.count { continue } + + let unusedInputs = + zip(instr.inputs, instr.outputs).filter { useCount[$0.1]! == 0 }.map { $0.0 } + for input in unusedInputs { + toRemove.insert(definitions[input]!) } - } - // Remove those candidates whose outputs are all used. - candidates = candidates.filter { - helper.code[$0].allOutputs.map({ uses[$0]! }).contains { $0 == 0 } + let newInouts = keptInoutsMap.map { $0.0 } + keptInoutsMap.map { $0.1 } + endTypeGroupReplacements[instr.index] = Instruction( + WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts, flags: .empty) } - if candidates.isEmpty { + if toRemove.isEmpty { return } - // Simplify each remaining candidate. - var replacements = [(Int, Instruction)]() - for candidate in candidates { - let instr = helper.code[candidate] - assert(instr.op is WasmEndTypeGroup) - assert(instr.inputs.count == instr.outputs.count) - let newInoutsMap = zip(instr.inputs, instr.outputs).filter { uses[$0.1]! > 0 } - let newInouts = newInoutsMap.map { $0.0 } + newInoutsMap.map { $0.1 } - let newInstr = Instruction( - WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) - replacements.append((candidate, newInstr)) - } - helper.tryReplacements(replacements, renumberVariables: true) + var newCode = Code( + helper.code + .filter { !toRemove.contains($0.index) } + .map { endTypeGroupReplacements[$0.index] ?? $0 }) + + newCode.renumberVariables() + helper.testAndCommit(newCode) } } diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 7ecaf6dbe..bdd149207 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -2521,7 +2521,7 @@ class MinimizerTests: XCTestCase { var numReturnsAfter = 0 var numFunctionsBefore = 0 var numFunctionsAfter = 0 - var numImportantInstructionsBefore = importantInstructions.count + let numImportantInstructionsBefore = importantInstructions.count var numImportantInstructionsAfter = 0 for instr in referenceProgram.code { @@ -2616,4 +2616,74 @@ class MinimizerTests: XCTestCase { program, withAspects: dummyAspects, limit: limit, performPostprocessing: performPostprocessing) } + + func testWasmTypeGroupMinimization() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + evaluator.nextInstructionIsImportant(in: b) + b.wasmDefineTypeGroup { + let v0 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) + return [v0] + } + let originalProgram = b.finalize() + + // Build expected output program: an empty type group. + b.reset() + b.wasmDefineTypeGroup { [] } + let expectedProgram = b.finalize() + + // Perform minimization with only the WasmTypeGroupReducer. + let reducer = WasmTypeGroupReducer() + evaluator.setOriginalProgram(originalProgram) + let helper = MinimizationHelper( + for: ProgramAspects(outcome: .succeeded), forCode: originalProgram.code, of: fuzzer, + runningOnFuzzerQueue: true) + reducer.reduce(with: helper) + + let actualProgram = Program(code: helper.code) + + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + } + + // Removing WasmResolveForwardReference is done by another reducer. The WasmTypeGroupReducer + // should not change the semantics when reducing the types exposed by the WasmEndTypeGroup. + func testWasmTypeGroupReducerDoesntRemoveForwardReferenceResolving() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + b.wasmDefineTypeGroup { + let fwd = b.wasmDefineForwardOrSelfReference() + evaluator.nextInstructionIsImportant(in: b) + let arrayType = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: fwd + ) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []) + b.wasmResolveForwardReference(fwd, to: structType) + return [structType, arrayType] + } + let originalProgram = b.finalize() + + // Perform minimization and check that the two programs are equal. + let reducer = WasmTypeGroupReducer() + evaluator.setOriginalProgram(originalProgram) + let helper = MinimizationHelper( + for: ProgramAspects(outcome: .succeeded), forCode: originalProgram.code, of: fuzzer, + runningOnFuzzerQueue: true) + reducer.reduce(with: helper) + let actualProgram = Program(code: helper.code) + + XCTAssertEqual( + originalProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(originalProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + } } From bc511f1bb5a85fbbf0f1e0332f736850745048b3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 12:07:22 +0200 Subject: [PATCH 036/223] [lifting] Remove invalid assert There isn't any escaping that prevents having property names containing new-lines and we do not escape them e.g. in the FuzzILLifter. This should be fine, the indentation might be ugly for it and in the JavaScriptLifter in the worst case we might create syntax errors but consistently and properly escaping string literals is not something that Fuzzilli seems to do (as of now). Change-Id: I974d10ecbe5d919b898e418815d8f72c199d0178 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206257 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Lifting/ScriptWriter.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Fuzzilli/Lifting/ScriptWriter.swift b/Sources/Fuzzilli/Lifting/ScriptWriter.swift index f9c029856..ec84c02b3 100644 --- a/Sources/Fuzzilli/Lifting/ScriptWriter.swift +++ b/Sources/Fuzzilli/Lifting/ScriptWriter.swift @@ -57,7 +57,6 @@ struct ScriptWriter { mutating func emit(_ line: S) { assert(maxLineLength > currentIndention.count) let splitAt = maxLineLength - currentIndention.count - assert(!line.contains("\n")) var line = line.prefix(line.count) while line.count > splitAt { var lineToPrint = line.prefix(splitAt + 1) From 31c547c7162255839c3e2484c3476457d35f4ab1 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 14:53:15 +0200 Subject: [PATCH 037/223] [v8] Remove wasm-in-js-inlining flag This feature isn't usable standalone any more, only as part of the turbolev pipeline. As such we'll be testing this implicitly via --turbolev-future (and eventually --turbolev once it's stable enough). Bug: 353475584, 455524488 Change-Id: I1f7566952c7fb33b20f59a58fd0795b5fa0bee16 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206258 Auto-Submit: Matthias Liedtke Reviewed-by: Daniel Lehmann Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 8919b7511..68478c62f 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -1069,10 +1069,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } } - if probability(0.1) { - args.append("--turboshaft-wasm-in-js-inlining") - } - if probability(0.1) { args.append("--harmony-struct") } From 91f2dda2d39b430fe5204fa0f4d2a3a66287c198 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 15 Apr 2026 16:14:53 +0000 Subject: [PATCH 038/223] Add FuzzilliCLI flag corpusGenerationIterations This allows to specify, e.g., --corpusGenerationIterations=1 such that the main fuzzing phase is triggered earlier. This can be helpful for quickly checking if a change causes a problem in the main fuzzing phase. Change-Id: Iedee6175b7fe15f677bb5a015aeeea555f7ce16b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9207316 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Configuration.swift | 6 ++++++ Sources/Fuzzilli/Fuzzer.swift | 2 +- Sources/FuzzilliCli/main.swift | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index d6fa2d311..4aa0f7b4a 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -97,6 +97,10 @@ public struct Configuration { // The directory in which the corpus and additional diagnostics files are stored. public let storagePath: String? + // The number of iterations without finding a new interesting program after which + // the fuzzer switches from corpus generation to the main fuzzing phase. + public let corpusGenerationIterations: Int + // Advises the fuzzer to generate cases that are more suitable for differential fuzzing. // Right now this only leads to the JavaScriptLifter emitting more local variables which // differential fuzzers can inspect (via mutating the JS program to print defined variables). @@ -121,6 +125,7 @@ public struct Configuration { tag: String? = nil, isWasmEnabled: Bool = false, storagePath: String? = nil, + corpusGenerationIterations: Int = 100, forDifferentialFuzzing: Bool = false, instanceId: Int = -1, dumplingEnabled: Bool = false @@ -138,6 +143,7 @@ public struct Configuration { self.tag = tag self.isWasmEnabled = isWasmEnabled self.storagePath = storagePath + self.corpusGenerationIterations = corpusGenerationIterations self.forDifferentialFuzzing = forDifferentialFuzzing self.diffConfig = dumplingEnabled diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 09b1ce265..4fb4f00cb 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -1069,7 +1069,7 @@ public class Fuzzer { // iterations. The rough order of magnitude of N has been determined experimentally: run two instances with // different values (e.g. 10 and 100) for roughly the same number of iterations (approximately until both // have finished the initial corpus generation), then compare the corpus size and coverage. - if iterationsSinceLastInterestingProgram > 100 { + if iterationsSinceLastInterestingProgram > config.corpusGenerationIterations { guard !corpus.isEmpty else { logger.fatal( "Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?" diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 8a95f081a..615825f21 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -48,6 +48,8 @@ if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != per round of sample selection. Used to ensure diversity between fuzzer instances (default: 0.10) --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). + --corpusGenerationIterations=n : Switch from corpus generation to the main fuzzing phase after this many + iterations without finding a new interesting sample (default: 100). --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions regardless of whether they are needed to trigger the interesting behaviour or not. See Minimizer.swift for an overview of this feature (default: 0.0). @@ -142,6 +144,7 @@ let minCorpusSize = args.int(for: "--minCorpusSize") ?? 1000 let maxCorpusSize = args.int(for: "--maxCorpusSize") ?? Int.max let markovDropoutRate = args.double(for: "--markovDropoutRate") ?? 0.10 let consecutiveMutations = args.int(for: "--consecutiveMutations") ?? 5 +let corpusGenerationIterations = args.int(for: "--corpusGenerationIterations") ?? 100 let minimizationLimit = args.double(for: "--minimizationLimit") ?? 0.0 let storagePath = args["--storagePath"] var resume = args.has("--resume") @@ -615,6 +618,7 @@ let mainConfig = Configuration( tag: tag, isWasmEnabled: enableWasm, storagePath: storagePath, + corpusGenerationIterations: corpusGenerationIterations, forDifferentialFuzzing: forDifferentialFuzzing, instanceId: 0, dumplingEnabled: profile.isDifferential) @@ -794,6 +798,7 @@ for i in 1.. Date: Wed, 15 Apr 2026 15:19:06 +0200 Subject: [PATCH 039/223] RuntimeAssistedMutator: Improve error message on failed transpilation The fuzzer should report whether node.js wasn't available or whether the npm dependencies were missing. This commit also changes the order of the two warnings, so we first print: > Mutated program did not crash, reporting original crash of the > instrumented program and then print any failures for trying to transpile the instrumented program. Bug: 488963988 Change-Id: I30fd95b8a0eaa10fb0050866cf5099e356086dd6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206260 Reviewed-by: Leon Bettscheider Commit-Queue: Matthias Liedtke --- .../Mutators/RuntimeAssistedMutator.swift | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 89845ff39..c9d3c383f 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -85,6 +85,43 @@ public class RuntimeAssistedMutator: Mutator { // May be overwritten by child classes } + // Lift the instrumented program to JS and try to transpile it back to FuzzIL. + // If we can convert the instrumented program including its additional JS code to IL, the crash + // reporting can perform proper minimization on it. + private func tryRoundtripTranspileInstrumentedProgramToFuzzIL( + _ fuzzer: Fuzzer, _ instrumentedProgram: Program + ) + -> Program? + { + let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) + var maybeProgramToMinimize: Program? = nil + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( + UUID().uuidString + ".js") + let errorPrefix = "Unable to compile instrumented JS program to FuzzIL because" + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + logger.warning("\(errorPrefix) node.js is not available") + return nil + } + guard let parser = JavaScriptParser(executor: nodejs) else { + logger.warning("\(errorPrefix) the needed npm dependencies are not installed") + return nil + } + do { + try instrumentedJavaScriptProgram.write( + to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + } + try? FileManager.default.removeItem(at: tempFile) + return maybeProgramToMinimize + } + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { @@ -155,38 +192,16 @@ public class RuntimeAssistedMutator: Mutator { } } - // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. - // First, get the instrumented JS program and try to compile it back to FuzzIL, so it can be minimized more effectively. - // We need this because instrumentation adds boilerplate JS code. - let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) - var maybeProgramToMinimize: Program? = nil - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( - UUID().uuidString + ".js") - if let nodejs = JavaScriptExecutor( - type: .nodejs, withArguments: ["--allow-natives-syntax"]), - let parser = JavaScriptParser(executor: nodejs) - { - do { - try instrumentedJavaScriptProgram.write( - to: tempFile, atomically: true, encoding: .utf8) - let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") - } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") - } - try? FileManager.default.removeItem(at: tempFile) - } else { - logger.warning( - "Unable to compile instrumented JS program to FuzzIL because node.js is not available" - ) - } - + // If we reach here, the process()'d program did not crash, so we need to report the + // instrumented program. logger.warning( "Mutated program did not crash, reporting original crash of the instrumented program" ) + let programToReport = + tryRoundtripTranspileInstrumentedProgramToFuzzIL(fuzzer, instrumentedProgram) + ?? instrumentedProgram fuzzer.processCrash( - maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, + programToReport, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: From d4c70b087cc3570c6233401e6f8ec8883691bc5d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 16:26:39 +0200 Subject: [PATCH 040/223] RuntimeAssistedMutator: Verify that the transpiled program still crashes There isn't any guarantee for that, in the worst case, removing comments can be enough to not encounter a crash any more (mostly in cases of moving gc-intervals as the JS code itself is part of the JS heap and therefore its size can affect reproducability.) Bug: 488963988 Change-Id: Id41eb32cc7517965c1de425e1d1be76ddd9f4370 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206261 Reviewed-by: Leon Bettscheider Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../Mutators/RuntimeAssistedMutator.swift | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index c9d3c383f..6dbf6e2c0 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -89,14 +89,14 @@ public class RuntimeAssistedMutator: Mutator { // If we can convert the instrumented program including its additional JS code to IL, the crash // reporting can perform proper minimization on it. private func tryRoundtripTranspileInstrumentedProgramToFuzzIL( - _ fuzzer: Fuzzer, _ instrumentedProgram: Program + _ fuzzer: Fuzzer, _ instrumentedProgram: Program, expectedSignal: Int ) -> Program? { let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) - var maybeProgramToMinimize: Program? = nil let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( UUID().uuidString + ".js") + defer { try? FileManager.default.removeItem(at: tempFile) } let errorPrefix = "Unable to compile instrumented JS program to FuzzIL because" guard let nodejs = JavaScriptExecutor( @@ -113,13 +113,25 @@ public class RuntimeAssistedMutator: Mutator { try instrumentedJavaScriptProgram.write( to: tempFile, atomically: true, encoding: .utf8) let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") + let transpiledProgram = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program back to FuzzIL") + let execution = fuzzer.execute( + transpiledProgram, withTimeout: fuzzer.config.timeout, + purpose: .runtimeAssistedMutation) + guard case .crashed(let signal) = execution.outcome else { + logger.warning("Transpiled program doesn't crash any more.") + return nil + } + guard signal == expectedSignal else { + logger.warning( + "Transpiled program crashes with signal \(signal) instead of \(expectedSignal)") + return nil + } + return transpiledProgram } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + logger.warning("Failed to compile instrumented JS program back to FuzzIL: \(error)") + return nil } - try? FileManager.default.removeItem(at: tempFile) - return maybeProgramToMinimize } override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) @@ -198,7 +210,8 @@ public class RuntimeAssistedMutator: Mutator { "Mutated program did not crash, reporting original crash of the instrumented program" ) let programToReport = - tryRoundtripTranspileInstrumentedProgramToFuzzIL(fuzzer, instrumentedProgram) + tryRoundtripTranspileInstrumentedProgramToFuzzIL( + fuzzer, instrumentedProgram, expectedSignal: signal) ?? instrumentedProgram fuzzer.processCrash( programToReport, withSignal: signal, From 267a742869730c92284be5be0b944136b44ab07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 16 Apr 2026 13:11:58 +0200 Subject: [PATCH 041/223] [js] Add bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bundles can contain multiple scripts which will be executed sequentially. Modules will be added as a follow up. Bug: 342521422 Change-Id: Icedae3b6805bf6db0359bb6fbdff69cfb2f0d48a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184296 Reviewed-by: Matthias Liedtke Commit-Queue: Marja Hölttä --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 39 +++++++++-- .../CodeGen/CodeGeneratorWeights.swift | 4 ++ Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 20 ++++++ Sources/Fuzzilli/Compiler/Compiler.swift | 6 +- Sources/Fuzzilli/Configuration.swift | 5 ++ Sources/Fuzzilli/Corpus/MarkovCorpus.swift | 3 +- .../Fuzzilli/Engines/GenerativeEngine.swift | 12 +++- .../Evaluation/ProgramCoverageEvaluator.swift | 2 +- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 13 +++- Sources/Fuzzilli/FuzzIL/Code.swift | 12 +++- Sources/Fuzzilli/FuzzIL/Context.swift | 6 ++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 8 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 14 ++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 17 +++++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 2 + Sources/Fuzzilli/FuzzIL/Program.swift | 7 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 2 + Sources/Fuzzilli/Fuzzer.swift | 57 +++++++++++----- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 8 +++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 20 ++++-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- .../Fuzzilli/Minimization/BlockReducer.swift | 9 +-- .../Minimization/DataFlowSimplifier.swift | 4 +- .../Minimization/InliningReducer.swift | 2 +- .../Minimization/InstructionSimplifier.swift | 2 +- .../Minimization/MinimizationHelper.swift | 2 +- .../MinimizationPostProcessor.swift | 2 +- .../Minimization/ReassignReducer.swift | 2 +- .../Minimization/WasmTypeGroupReducer.swift | 2 +- Sources/Fuzzilli/Modules/Sync.swift | 10 +++ .../Fuzzilli/Mutators/OperationMutator.swift | 2 + Sources/Fuzzilli/Protobuf/gen_programproto.py | 1 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 58 ++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 6 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 68 ++++++++++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 3 + Sources/Fuzzilli/Protobuf/sync.pb.swift | 9 ++- Sources/Fuzzilli/Protobuf/sync.proto | 1 + Sources/FuzzilliCli/main.swift | 14 +++- Tests/FuzzilliTests/ContextGraphTest.swift | 21 +++++- Tests/FuzzilliTests/LifterTest.swift | 30 ++++++++ Tests/FuzzilliTests/MinimizerTest.swift | 42 +++++++++++- Tests/FuzzilliTests/ProgramBuilderTest.swift | 39 +++++++++++ 43 files changed, 520 insertions(+), 68 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index e3bf101f0..44cc8f64a 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -58,7 +58,7 @@ public class ProgramBuilder { private let logger = Logger(withLabel: "ProgramBuilder") /// The code and type information of the program that is being constructed. - private var code = Code() + private var code: Code /// Comments for the program that is being constructed. private var comments = ProgramComments() @@ -77,7 +77,7 @@ public class ProgramBuilder { private var numVariables = 0 /// Context analyzer to keep track of the currently active IL context. - private var contextAnalyzer = ContextAnalyzer() + private var contextAnalyzer: ContextAnalyzer /// Visible variables management. /// The `scopes` stack contains one entry per currently open scope containing all variables created in that scope. @@ -191,15 +191,20 @@ public class ProgramBuilder { } } + public let isBundle: Bool + /// Constructs a new program builder for the given fuzzer. - init(for fuzzer: Fuzzer, parent: Program?) { + init(for fuzzer: Fuzzer, parent: Program?, isBundle: Bool) { self.fuzzer = fuzzer - self.jsTyper = JSTyper(for: fuzzer.environment) + self.jsTyper = JSTyper(for: fuzzer.environment, isBundle: isBundle) self.parent = parent + self.isBundle = isBundle if fuzzer.config.logLevel.isAtLeast(.verbose) { self.buildLog = BuildLog() } + code = Code(isBundle: isBundle) + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) } /// Resets this builder. @@ -212,7 +217,7 @@ public class ProgramBuilder { variablesInScope.removeAll() hiddenVariables.removeAll() numberOfHiddenVariables = 0 - contextAnalyzer = ContextAnalyzer() + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) jsTyper.reset() activeObjectLiterals.removeAll() activeClassDefinitions.removeAll() @@ -1106,6 +1111,10 @@ public class ProgramBuilder { /// Returns a random variable satisfying the given constraints or nil if none is found. public func findVariable(satisfying filter: ((Variable) -> Bool) = { _ in true }) -> Variable? { + if isBundle && !hasVisibleVariables { + // Bundles don't have visible variables before we've started generating the bundle items. + return nil + } assert(hasVisibleVariables) // TODO: we should implement some kind of fast lookup data structure to speed up the lookup of variables by type. @@ -1730,7 +1739,7 @@ public class ProgramBuilder { // Step (2): determine which instructions can be part of the slice and attempt to find replacement variables for the outputs of instructions that cannot be included. // // We need a typer to be able to find compatible replacement variables if we are merging the dataflows of the two programs. - var typer = JSTyper(for: fuzzer.environment) + var typer = JSTyper(for: fuzzer.environment, isBundle: program.code.isBundle) // The set of variables that are available for a slice. A variable is available either because the instruction that outputs // it can be part of the slice or because the variable has been remapped to a host variable. var availableVariables = VariableSet() @@ -2097,8 +2106,9 @@ public class ProgramBuilder { case .generating: // This requirement might seem somewhat arbitrary but our JavaScript code generators make use of `b.randomVariable` and as such rely on the availability of // visible Variables. Therefore we should always have some Variables visible if we want to use them. + assert( - hasVisibleVariables, + isBundle || hasVisibleVariables, "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program" ) @@ -2244,6 +2254,11 @@ public class ProgramBuilder { /// of prefix code is controlled in the same way as other generated code through the /// generator's respective weights. public func buildPrefix() { + if contextAnalyzer.context == .bundle { + // Don't emit a prefix into the bundle context. The items inside the bundle will emit their own prefixes. + return + } + // Each value generators should generate at least 3 variables, and we probably want to run at least a // few of them (maybe roughly >= 3), so the number of variables to build shouldn't be set too low. assert(GeneratorStub.numberOfValuesToGenerateByValueGenerators == 3) @@ -4060,6 +4075,16 @@ public class ProgramBuilder { emit(EndBlockStatement()) } + public func maybeWrapInsideBundleScript(_ body: () -> Void) { + if isBundle { + emit(BeginBundleScript()) + } + body() + if isBundle { + emit(EndBundleScript()) + } + } + public func doPrint(_ value: Variable) { emit(Print(), withInputs: [value]) } diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 69a29a2ef..f607ba62d 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -236,6 +236,10 @@ public let codeGeneratorWeights = [ "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, + // For generating bundles + // TODO(marja): Add modules. + "BundleScriptGenerator": 1, + // // Wasm generators // diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index cdc4863d0..8bc94f6db 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -3394,4 +3394,24 @@ public let CodeGenerators: [CodeGenerator] = [ let newSize = b.binary(currentByteLength, delta, with: .Add) b.callMethod("grow", on: buffer, withArgs: [newSize], guard: true) }, + + CodeGenerator( + "BundleScriptGenerator", + [ + GeneratorStub( + "BundleScriptBeginGenerator", + inContext: .single(.bundle), + provides: [.javascript] + ) { b in + b.emit(BeginBundleScript()) + // TODO(marja): Make variables created to scripts visible to other scripts. + b.buildPrefix() + }, + GeneratorStub( + "BundleScriptEndGenerator", + inContext: .single([.javascript]), + ) { b in + b.emit(EndBundleScript()) + }, + ]), ] diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 188868063..1ecdf89e6 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -31,7 +31,8 @@ public class JavaScriptCompiler { public init() {} /// The compiled code. - private var code = Code() + // TODO(marja): Make JavaScriptCompiler understand bundles. + private var code = Code(isBundle: false) /// The environment is used to determine if an identifier identifies a builtin object. /// TODO we should probably use the correct target environment, with any additional builtins etc. here. But for now, we just manually add `gc` since that's relatively common. @@ -1559,7 +1560,8 @@ public class JavaScriptCompiler { } private func reset() { - code = Code() + // TODO(marja): Make JavaScriptCompiler understand bundles. + code = Code(isBundle: false) scopes.removeAll() nextVariable = 0 } diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 4aa0f7b4a..efd048ddf 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -110,6 +110,9 @@ public struct Configuration { // be imported due to disabled wasm capabilities in the fuzzer. public static let excludedWasmDirectory = "excluded_wasm_programs" + // Whether the fuzzer generates bundles containing multiple JavaScript scripts or modules. + public let generateBundle: Bool + public init( arguments: [String] = [], timeout: UInt32 = 250, @@ -124,6 +127,7 @@ public struct Configuration { staticCorpus: Bool = false, tag: String? = nil, isWasmEnabled: Bool = false, + generateBundle: Bool = false, storagePath: String? = nil, corpusGenerationIterations: Int = 100, forDifferentialFuzzing: Bool = false, @@ -142,6 +146,7 @@ public struct Configuration { self.staticCorpus = staticCorpus self.tag = tag self.isWasmEnabled = isWasmEnabled + self.generateBundle = generateBundle self.storagePath = storagePath self.corpusGenerationIterations = corpusGenerationIterations self.forDifferentialFuzzing = forDifferentialFuzzing diff --git a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift index bbc069983..2224f593c 100644 --- a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift +++ b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift @@ -51,7 +51,8 @@ public class MarkovCorpus: ComponentBase, Corpus { self.dropoutRate = dropoutRate covEvaluator.enableEdgeTracking() self.covEvaluator = covEvaluator - self.currentProg = Program() + // TODO(marja): Support bundles. + self.currentProg = Program(isBundle: false) super.init(name: "MarkovCorpus") } diff --git a/Sources/Fuzzilli/Engines/GenerativeEngine.swift b/Sources/Fuzzilli/Engines/GenerativeEngine.swift index f2a5115ee..a0c21aadf 100644 --- a/Sources/Fuzzilli/Engines/GenerativeEngine.swift +++ b/Sources/Fuzzilli/Engines/GenerativeEngine.swift @@ -17,9 +17,12 @@ import Foundation /// Purely generative fuzzing engine, mostly used for initial corpus generation when starting without an existing corpus. public class GenerativeEngine: FuzzEngine { /// Approximate number of instructions to generate in additional to any prefix code. - private let numInstructionsToGenerate = 10 + private var numInstructionsToGenerate = 10 - public init() { + private let generateBundle: Bool + + public init(generateBundle: Bool) { + self.generateBundle = generateBundle super.init(name: "GenerativeEngine") } @@ -27,6 +30,11 @@ public class GenerativeEngine: FuzzEngine { public override func fuzzOne(_ group: DispatchGroup) { let b = fuzzer.makeBuilder() + if generateBundle { + // Increase the budget so that we are more likely to generate more items inside a bundle. + numInstructionsToGenerate = 50 + } + // Start by building a prefix that creates some variables (of known types) that the following CodeGenerators can then make use of. b.buildPrefix() // Then generate the actual code. diff --git a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift index 4decc2812..447db8043 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift @@ -150,7 +150,7 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { libcoverage.cov_shutdown(&self.context) } - let _ = fuzzer.execute(Program(), purpose: .startup) + let _ = fuzzer.execute(Program(isBundle: false), purpose: .startup) libcoverage.cov_finish_initialization(&context, shouldTrackEdgeCounts ? 1 : 0) logger.info("Initialized, \(context.num_edges) edges") } diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index aabce9662..ce6edb562 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -37,7 +37,7 @@ extension Analyzer { struct DefUseAnalyzer: Analyzer { private var assignments = VariableMap<[Int]>() private var uses = VariableMap<[Int]>() - private var code = Code() + private var code: Code private var isRunning = true private var analysisDone = false @@ -46,7 +46,9 @@ struct DefUseAnalyzer: Analyzer { self.isRunning = false } - init() {} + init(isBundle: Bool) { + self.code = Code(isBundle: isBundle) + } mutating func finishAnalysis() { analysisDone = true @@ -161,12 +163,17 @@ struct VariableAnalyzer: Analyzer { /// Keeps track of the current context during program construction. struct ContextAnalyzer: Analyzer { - private var contextStack = Stack([Context.javascript]) + private var contextStack: Stack var context: Context { return contextStack.top } + public init(isBundle: Bool = false) { + let startingContext = isBundle ? Context.bundle : Context.javascript + contextStack = Stack([startingContext]) + } + mutating func analyze(_ instr: Instruction) { if instr.isBlockEnd { contextStack.pop() diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index b0229396c..199ec341a 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -22,11 +22,17 @@ public struct Code: Collection { /// Code is just a linear sequence of instructions. private var instructions = [Instruction]() + public let isBundle: Bool + /// Creates an empty code instance. - public init() {} + public init(isBundle: Bool) { + self.isBundle = isBundle + } /// Creates a code instance containing the given instructions. - public init(_ instructions: S) where S.Element == Instruction { + public init(_ instructions: S, isBundle: Bool) + where S.Element == Instruction { + self.isBundle = isBundle for instr in instructions { append(instr) } @@ -205,7 +211,7 @@ public struct Code: Collection { /// Checks if this code is statically valid, i.e. can be used as a Program. public func check() throws { var definedVariables = VariableMap() - var contextAnalyzer = ContextAnalyzer() + var contextAnalyzer = ContextAnalyzer(isBundle: isBundle) var scopeCounter = 0 // Per-block information is stored in this struct and kept in a stack of active blocks. struct Block { diff --git a/Sources/Fuzzilli/FuzzIL/Context.swift b/Sources/Fuzzilli/FuzzIL/Context.swift index 080c3d5e8..3bf4dd5b4 100644 --- a/Sources/Fuzzilli/FuzzIL/Context.swift +++ b/Sources/Fuzzilli/FuzzIL/Context.swift @@ -30,6 +30,7 @@ public struct Context: OptionSet, Hashable, CaseIterable { .wasmFunction, .wasmTypeGroup, .empty, + .bundle, ] public let rawValue: UInt32 @@ -71,6 +72,8 @@ public struct Context: OptionSet, Hashable, CaseIterable { public static let wasmFunction = Context(rawValue: 1 << 12) // Inside a wasm recursive type group definition. public static let wasmTypeGroup = Context(rawValue: 1 << 13) + // Inside a bundle containing multiple scripts / modules + public static let bundle = Context(rawValue: 1 << 14) public static let empty = Context([]) @@ -115,6 +118,9 @@ extension Context: CustomStringConvertible { if self.contains(.switchCase) { strings.append(".switchCase") } + if self.contains(.bundle) { + strings.append(".bundle") + } if self.contains(.wasm) { strings.append(".wasm") } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index be087fdc3..3cc539e93 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1194,6 +1194,10 @@ extension Instruction: ProtobufConvertible { $0.bindMethod = Fuzzilli_Protobuf_BindMethod.with { $0.methodName = op.methodName } case .bindFunction(_): $0.bindFunction = Fuzzilli_Protobuf_BindFunction() + case .beginBundleScript: + $0.beginBundleScript = Fuzzilli_Protobuf_BeginBundleScript() + case .endBundleScript: + $0.endBundleScript = Fuzzilli_Protobuf_EndBundleScript() case .print(_): fatalError("Print operations should not be serialized") // Wasm Operations @@ -2378,6 +2382,10 @@ extension Instruction: ProtobufConvertible { op = BeginBlockStatement() case .endBlockStatement: op = EndBlockStatement() + case .beginBundleScript: + op = BeginBundleScript() + case .endBundleScript: + op = EndBundleScript() case .loadNewTarget: op = LoadNewTarget() case .nop: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index f3519b16f..078e34378 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -25,7 +25,7 @@ public struct JSTyper: Analyzer { // The current state private var state = AnalyzerState() - private var defUseAnalyzer = DefUseAnalyzer() + private var defUseAnalyzer: DefUseAnalyzer // Parameter types for subroutines defined in the analyzed program. // These are keyed by the index of the start of the subroutine definition. @@ -441,8 +441,12 @@ public struct JSTyper: Analyzer { // The index of the last instruction that was processed. Just used for debug assertions. private var indexOfLastInstruction = -1 - init(for environ: JavaScriptEnvironment) { + private let isBundle: Bool + + init(for environ: JavaScriptEnvironment, isBundle: Bool) { self.environment = environ + self.isBundle = isBundle + self.defUseAnalyzer = DefUseAnalyzer(isBundle: isBundle) } public mutating func reset() { @@ -451,7 +455,7 @@ public struct JSTyper: Analyzer { signatures.removeAll() typeGroups.removeAll() wasmTypeDefMap.removeAll() - defUseAnalyzer = DefUseAnalyzer() + defUseAnalyzer = DefUseAnalyzer(isBundle: isBundle) isWithinTypeGroup = false dynamicObjectGroupManager = ObjectGroupManager() assert(activeFunctionDefinitions.isEmpty) @@ -1379,7 +1383,9 @@ public struct JSTyper: Analyzer { .beginClassStaticInitializer, .endClassStaticInitializer, .beginWasmModule, - .endWasmModule: + .endWasmModule, + .beginBundleScript, + .endBundleScript: // Object literals and class definitions don't create any conditional branches, only methods and accessors inside of them. These are handled further below. break case .beginIf: diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index be392b830..14e74f42d 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -2624,6 +2624,23 @@ final class LoadNewTarget: JsOperation { } } +final class BeginBundleScript: JsOperation { + override var opcode: Opcode { .beginBundleScript(self) } + + init() { + super.init( + attributes: .isBlockStart, requiredContext: [.bundle], contextOpened: .javascript) + } +} + +final class EndBundleScript: JsOperation { + override var opcode: Opcode { .endBundleScript(self) } + + init() { + super.init(attributes: .isBlockEnd, requiredContext: .javascript) + } +} + final class BeginWasmModule: JsOperation { override var opcode: Opcode { .beginWasmModule(self) } init() { diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 3a55fc4cb..deb4011bc 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -363,4 +363,6 @@ enum Opcode { case endClassComputedGetter(EndClassComputedGetter) case beginClassComputedSetter(BeginClassComputedSetter) case endClassComputedSetter(EndClassComputedSetter) + case beginBundleScript(BeginBundleScript) + case endBundleScript(EndBundleScript) } diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index 9b2c81122..f7e4e4b58 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -47,8 +47,8 @@ public final class Program: CustomStringConvertible { public private(set) lazy var id = UUID() /// Constructs an empty program. - public init() { - self.code = Code() + public init(isBundle: Bool) { + self.code = Code(isBundle: isBundle) self.parent = nil } @@ -141,6 +141,7 @@ extension Program: ProtobufConvertible { if let parent = parent { $0.parent = parent.asProtobuf(opCache: opCache) } + $0.isBundle = code.isBundle } } @@ -149,7 +150,7 @@ extension Program: ProtobufConvertible { } convenience init(from proto: ProtobufType, opCache: OperationCache? = nil) throws { - var code = Code() + var code = Code(isBundle: proto.isBundle) for (i, protoInstr) in proto.code.enumerated() { do { code.append(try Instruction(from: protoInstr, with: opCache)) diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index f8a60233c..325524ca3 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -221,6 +221,8 @@ extension Operation { return endOp is EndCodeString case .beginBlockStatement: return endOp is EndBlockStatement + case .beginBundleScript: + return endOp is EndBundleScript case .beginWasmModule: return endOp is EndWasmModule case .beginWasmFunction: diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 4fb4f00cb..7a2d93ab5 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -87,7 +87,7 @@ public class Fuzzer { public let minimizer: Minimizer /// The engine used for initial corpus generation (if performed). - public let corpusGenerationEngine = GenerativeEngine() + public let corpusGenerationEngine: GenerativeEngine /// The possible states of a fuzzer. public enum State { @@ -212,6 +212,7 @@ public class Fuzzer { self.logger = Logger(withLabel: "Fuzzer") self.contextGraph = ContextGraph(for: codeGenerators, withLogger: self.logger) + self.corpusGenerationEngine = GenerativeEngine(generateBundle: configuration.generateBundle) // Pass-through any postprocessor to the generative engine. if let postProcessor = engine.postProcessor { corpusGenerationEngine.registerPostProcessor(postProcessor) @@ -449,6 +450,7 @@ public class Fuzzer { case imported case dropped case needsWasm + case needsBundles case failed(ExecutionOutcome) } @@ -487,6 +489,10 @@ public class Fuzzer { return .needsWasm } + if !config.generateBundle && program.code.isBundle { + return .needsBundles + } + let execution = execute(program, purpose: .programImport) var wasImported = false @@ -622,7 +628,7 @@ public class Fuzzer { // Only attempt fixup if the program failed to execute successfully. In particular, ignore timeouts and // crashes here, but also take into account that not all successfully executing programs will be imported. switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 0) case .failed(_): break @@ -646,7 +652,7 @@ public class Fuzzer { program = removeCallsTo(filteredFunctions, from: program) result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 1) case .failed(_): break @@ -667,7 +673,7 @@ public class Fuzzer { } result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 2) case .failed(_): break @@ -949,7 +955,7 @@ public class Fuzzer { dispatchPrecondition(condition: .onQueue(queue)) // Program ancestor chains are only constructed if inspection mode is enabled let parent = config.enableInspection ? parent : nil - return ProgramBuilder(for: self, parent: parent) + return ProgramBuilder(for: self, parent: parent, isBundle: config.generateBundle) } /// Performs one round of fuzzing. @@ -1038,6 +1044,11 @@ public class Fuzzer { ) } } + if !config.generateBundle { + logger.info( + "\(currentCorpusImportJob.numberOfProgramsRequiringBundlesButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require bundles which are disabled" + ) + } let successRatio = Double( @@ -1048,7 +1059,7 @@ public class Fuzzer { let reason = config.isWasmEnabled ? "execute successfully" - : "execute successfully or require currently disabled wasm" + : "execute successfully or require currently disabled wasm or bundles" logger.warning( "\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported." ) @@ -1093,9 +1104,7 @@ public class Fuzzer { } /// Constructs a non-trivial program. Useful to measure program execution speed. - private func makeComplexProgram() -> Program { - let b = makeBuilder() - + private func makeComplexProgram(builder b: ProgramBuilder) { let f = b.buildPlainFunction(with: .parameters(n: 2)) { params in let x = b.getProperty("x", of: params[0]) let y = b.getProperty("y", of: params[0]) @@ -1111,8 +1120,6 @@ public class Fuzzer { let arg2 = i b.callFunction(f, withArgs: [arg1, arg2]) } - - return b.finalize() } /// Runs a number of startup tests to check whether everything is configured correctly. @@ -1121,7 +1128,7 @@ public class Fuzzer { assert(isInitialized) // Check if we can execute programs - var execution = execute(Program(), purpose: .startup) + var execution = execute(Program(isBundle: false), purpose: .startup) guard case .succeeded = execution.outcome else { logger.fatal( "Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?" @@ -1130,8 +1137,10 @@ public class Fuzzer { // Check if we can detect failed executions (i.e. an exception was thrown) var b = makeBuilder() - let exception = b.loadInt(42) - b.throwException(exception) + b.maybeWrapInsideBundleScript { + let exception = b.loadInt(42) + b.throwException(exception) + } execution = execute(b.finalize(), purpose: .startup) guard case .failed = execution.outcome else { logger.fatal( @@ -1141,7 +1150,10 @@ public class Fuzzer { var maxExecutionTime: TimeInterval = 0 // Dispatch a non-trivial program and measure its execution time - let complexProgram = makeComplexProgram() + b.maybeWrapInsideBundleScript { + makeComplexProgram(builder: b) + } + let complexProgram = b.finalize() for _ in 0..<5 { let execution = execute(complexProgram, purpose: .startup) maxExecutionTime = max(maxExecutionTime, execution.execTime) @@ -1151,7 +1163,9 @@ public class Fuzzer { var hasAnyCrashTests = false for (test, expectedResult) in config.startupTests { b = makeBuilder() - b.eval(test) + b.maybeWrapInsideBundleScript { + b.eval(test) + } execution = execute(b.finalize(), purpose: .startup) if execution.outcome == .timedOut { @@ -1184,6 +1198,8 @@ public class Fuzzer { } } + // TODO(marja): when we have modules, add a "bundles" startup test which asserts that bundles are handled correctly. + if !hasAnyCrashTests { logger.warning( "Cannot check if crashes are detected as there are no startup tests that should cause a crash" @@ -1216,8 +1232,10 @@ public class Fuzzer { // Check if we can receive program output b = makeBuilder() - let str = b.loadString("Hello World!") - b.doPrint(str) + b.maybeWrapInsideBundleScript { + let str = b.loadString("Hello World!") + b.doPrint(str) + } let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters( in: .whitespacesAndNewlines) if output != "Hello World!" { @@ -1312,6 +1330,7 @@ public class Fuzzer { private(set) var numberOfProgramsThatNeededTwoFixupAttempts = 0 private(set) var numberOfProgramsThatNeededThreeFixupAttempts = 0 private(set) var numberOfProgramsRequiringWasmButDisabled = 0 + private(set) var numberOfProgramsRequiringBundlesButDisabled = 0 var numberOfProgramsThatNeededFixup: Int { assert(Fuzzer.maxProgramImportFixupAttempts == 3) @@ -1354,6 +1373,8 @@ public class Fuzzer { break case .needsWasm: numberOfProgramsRequiringWasmButDisabled += 1 + case .needsBundles: + numberOfProgramsRequiringBundlesButDisabled += 1 case .failed(let outcome): switch outcome { case .crashed, .succeeded, .differential: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 2cc5d9465..dc7d7af68 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -817,6 +817,14 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndBlockStatement") + case .beginBundleScript: + w.emit("BeginBundleScript") + w.increaseIndentionLevel() + + case .endBundleScript: + w.decreaseIndentionLevel() + w.emit("EndBundleScript") + case .loadNewTarget: w.emit("\(output()) <- LoadNewTarget") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 6a733fac2..858c62af5 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -113,7 +113,7 @@ public class JavaScriptLifter: Lifter { // This typer is shared across WasmLifters and a WasmLifter is only valid for a single WasmModule. var typer: JSTyper? = nil // The currently active WasmLifter, we can only have one of them. - var wasmInstructions = Code() + var wasmInstructions = Code(isBundle: false) // Map block start index to end index. let blockEndIndices = program.code.reduce( @@ -139,7 +139,7 @@ public class JavaScriptLifter: Lifter { if needToSupportWasm { // If we need to support Wasm we need to type all instructions outside of Wasm such that the WasmLifter can access extra type information during lifting. - typer = JSTyper(for: environment) + typer = JSTyper(for: environment, isBundle: program.code.isBundle) } var w = JavaScriptWriter( @@ -235,7 +235,8 @@ public class JavaScriptLifter: Lifter { wasmTypeGroupStarts = instr.index } else if instr.op is WasmEndTypeGroup { w.emitComment("Wasm type group:") - let code = Code(program.code[wasmTypeGroupStarts!...instr.index]) + let code = Code( + program.code[wasmTypeGroupStarts!...instr.index], isBundle: false) wasmTypeGroupStarts = nil w.emitComment(FuzzILLifter().lift(code)) } @@ -1514,6 +1515,12 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") + case .beginBundleScript: + w.emitRaw("// JS_BUNDLE_SCRIPT") + + case .endBundleScript: + break + case .loadNewTarget: w.assign(Identifier.new("new.target"), to: instr.output) @@ -1579,7 +1586,7 @@ public class JavaScriptLifter: Lifter { case .endWasmModule: // Lift the FuzzILCode of this Block first. w.emitComment("WasmModule Code:") - let code = Code(program.code[wasmCodeStarts!...instr.index]) + let code = Code(program.code[wasmCodeStarts!...instr.index], isBundle: false) wasmCodeStarts = nil w.emitComment(FuzzILLifter().lift(code)) @@ -2474,6 +2481,11 @@ public class JavaScriptLifter: Lifter { writer.emitBlock(line) } + mutating func emitRaw(_ line: String) { + emitPendingExpressions() + writer.emit(line) + } + /// Emit a (potentially multi-line) comment. mutating func emitComment(_ comment: String) { writer.emitComment(comment) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 13f91758d..a5a0232f3 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -257,7 +257,7 @@ public class WasmLifter { private var typer: JSTyper // This contains the instructions that we need to lift. - private var instructionBuffer: Code = Code() + private var instructionBuffer: Code = Code(isBundle: false) // TODO(cffsmith): we could do some checking here that the function is actually defined, at that point it would not be static anymore though. private static func nameOfFunction(_ idx: Int) -> String { diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 39f27e327..5af1d5e3e 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -90,7 +90,8 @@ struct BlockReducer: Reducer { .beginWasmFunction, .beginWasmModule, .wasmBeginTryDelegate, - .wasmBeginTryTable: + .wasmBeginTryTable, + .beginBundleScript: reduceGenericBlockGroup(group, with: helper) case .wasmBeginBlock, @@ -347,7 +348,7 @@ struct BlockReducer: Reducer { varReplacements.merge( zip(endInstr.outputs, endInstrInputs.map { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == group.head || i == group.tail { continue // Skip the block begin and end. @@ -542,7 +543,7 @@ struct BlockReducer: Reducer { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == ifBlock.head || (i >= elseBlock.head && i <= elseBlock.tail) { continue // Skip the WasmBeginIf and the else block. @@ -572,7 +573,7 @@ struct BlockReducer: Reducer { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == elseBlock.tail || (i >= ifBlock.head && i <= ifBlock.tail) { continue // Skip the WasmBeginIf and the if true block. diff --git a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift index c1a4357c4..5263ef11d 100644 --- a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift @@ -31,7 +31,7 @@ /// roughly the right type. struct DataFlowSimplifier: Reducer { func reduce(with helper: MinimizationHelper) { - var typer = JSTyper(for: helper.fuzzer.environment) + var typer = JSTyper(for: helper.fuzzer.environment, isBundle: helper.code.isBundle) var candidates = [Int]() var uses = VariableMap() for instr in helper.code { @@ -83,7 +83,7 @@ struct DataFlowSimplifier: Reducer { // Finally try to remove each remaining candidate. for candidate in candidates { - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var replacements = VariableMap() for instr in helper.code { if instr.index == candidate { diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 731478c45..94f81e904 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -145,7 +145,7 @@ struct InliningReducer: Reducer { assert(index < code.count) assert(code[index].op is BeginAnyFunction) - var c = Code() + var c = Code(isBundle: code.isBundle) var i = 0 // Append all code prior to the function that we're inlining. diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index da9d32ad3..2126359d7 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -127,7 +127,7 @@ struct InstructionSimplifier: Reducer { // All simplifications are performed at once to keep this logic simple. // This logic needs to be somewhat careful not to perform no-op replacements as // these would cause the fixpoint iteration to not terminate. - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var numCopiedInstructions = 0 for instr in helper.code { var keepInstruction = true diff --git a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift index 440a98ae5..80691a669 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift @@ -195,7 +195,7 @@ class MinimizationHelper { assert(newInstr.flags.isEmpty) // For simplicity, just build a copy of the input code here. This logic is not particularly performance sensitive. - var newCode = Code() + var newCode = Code(isBundle: code.isBundle) for instr in code { if instr.index == index { newCode.append(newInstr) diff --git a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift index 45180278c..594c621bb 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift @@ -25,7 +25,7 @@ struct MinimizationPostProcessor { func process(with helper: MinimizationHelper) -> Bool { // Step 1: Generate all changes that we'd like to perform and record them. var changes = [(index: Int, newInstruction: Instruction)]() - var codeWithNops = Code() + var codeWithNops = Code(isBundle: helper.code.isBundle) // This must happen on the fuzzer's queue as it requires a ProgramBuilder to obtain input variables. helper.performOnFuzzerQueue { diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index c6a290d08..e473f28c1 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -45,7 +45,7 @@ struct ReassignmentReducer: Reducer { func reduce(with helper: MinimizationHelper) { var reassignedVariables = VariableMap() var reassignedVariableStack: [[Variable]] = [[]] - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var didChangeCode = false for instr in helper.code { diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 85f93525a..50f2c5eac 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -85,7 +85,7 @@ struct WasmTypeGroupReducer: Reducer { var newCode = Code( helper.code .filter { !toRemove.contains($0.index) } - .map { endTypeGroupReplacements[$0.index] ?? $0 }) + .map { endTypeGroupReplacements[$0.index] ?? $0 }, isBundle: helper.code.isBundle) newCode.renumberVariables() helper.testAndCommit(newCode) diff --git a/Sources/Fuzzilli/Modules/Sync.swift b/Sources/Fuzzilli/Modules/Sync.swift index d21b68d8c..e45507e61 100644 --- a/Sources/Fuzzilli/Modules/Sync.swift +++ b/Sources/Fuzzilli/Modules/Sync.swift @@ -137,6 +137,7 @@ public class DistributedFuzzingNode { $0.corpus = try fuzzer.corpus.exportState() $0.evaluatorState = fuzzer.evaluator.exportState() $0.isWasmEnabled = fuzzer.config.isWasmEnabled + $0.areBundlesEnabled = fuzzer.config.generateBundle } return try state.serializedData() } else { @@ -166,6 +167,15 @@ public class DistributedFuzzingNode { ) } + if state.areBundlesEnabled != fuzzer.config.generateBundle { + // Ditto for bundles. + let parentState = fuzzer.config.generateBundle ? "enabled" : "disabled" + let selfState = state.areBundlesEnabled ? "enabled" : "disabled" + throw FuzzilliError.corpusImportError( + "Inconsistent state between distributed nodes: The parent has bundles \(parentState) while the current fuzzer has wasm \(selfState)!" + ) + } + try fuzzer.corpus.importState(state.corpus) try fuzzer.evaluator.importState(state.evaluatorState) } else { diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 1ce56d0c8..613b68e1a 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -748,6 +748,8 @@ public class OperationMutator: BaseInstructionMutator { .wrapSuspending(_), .bindMethod(_), .bindFunction(_), + .beginBundleScript(_), + .endBundleScript(_), // Wasm instructions .beginWasmModule(_), .endWasmModule(_), diff --git a/Sources/Fuzzilli/Protobuf/gen_programproto.py b/Sources/Fuzzilli/Protobuf/gen_programproto.py index 7447d6caf..2055904e9 100644 --- a/Sources/Fuzzilli/Protobuf/gen_programproto.py +++ b/Sources/Fuzzilli/Protobuf/gen_programproto.py @@ -48,6 +48,7 @@ repeated Instruction code = 2; map comments = 3; Program parent = 4; + bool isBundle = 5; } """ diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index cc4bafbf1..97800aa14 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -6008,6 +6008,26 @@ public struct Fuzzilli_Protobuf_WasmTableCopy: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginBundleScript: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndBundleScript: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "fuzzilli.protobuf" @@ -15547,3 +15567,41 @@ extension Fuzzilli_Protobuf_WasmTableCopy: SwiftProtobuf.Message, SwiftProtobuf. return true } } + +extension Fuzzilli_Protobuf_BeginBundleScript: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginBundleScript" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginBundleScript, rhs: Fuzzilli_Protobuf_BeginBundleScript) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndBundleScript: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndBundleScript" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndBundleScript, rhs: Fuzzilli_Protobuf_EndBundleScript) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index c654f8b6f..cdb4eb12f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1672,3 +1672,9 @@ message WasmTableInit { message WasmTableCopy { } + +message BeginBundleScript { +} + +message EndBundleScript { +} \ No newline at end of file diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index a610786ae..a84249e86 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2721,6 +2721,22 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassComputedSetter(newValue)} } + public var beginBundleScript: Fuzzilli_Protobuf_BeginBundleScript { + get { + if case .beginBundleScript(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginBundleScript() + } + set {operation = .beginBundleScript(newValue)} + } + + public var endBundleScript: Fuzzilli_Protobuf_EndBundleScript { + get { + if case .endBundleScript(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndBundleScript() + } + set {operation = .endBundleScript(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3058,6 +3074,8 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case endClassComputedGetter(Fuzzilli_Protobuf_EndClassComputedGetter) case beginClassComputedSetter(Fuzzilli_Protobuf_BeginClassComputedSetter) case endClassComputedSetter(Fuzzilli_Protobuf_EndClassComputedSetter) + case beginBundleScript(Fuzzilli_Protobuf_BeginBundleScript) + case endBundleScript(Fuzzilli_Protobuf_EndBundleScript) } @@ -3093,6 +3111,11 @@ public struct Fuzzilli_Protobuf_Program: @unchecked Sendable { /// Clears the value of `parent`. Subsequent reads from it will return its default value. public mutating func clearParent() {_uniqueStorage()._parent = nil} + public var isBundle: Bool { + get {_storage._isBundle} + set {_uniqueStorage()._isBundle = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -3106,7 +3129,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0\u{1}beginBundleScript\0\u{1}endBundleScript\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7452,6 +7475,32 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endClassComputedSetter(v) } }() + case 336: try { + var v: Fuzzilli_Protobuf_BeginBundleScript? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginBundleScript(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginBundleScript(v) + } + }() + case 337: try { + var v: Fuzzilli_Protobuf_EndBundleScript? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endBundleScript(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endBundleScript(v) + } + }() default: break } } @@ -8802,6 +8851,14 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endClassComputedSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 335) }() + case .beginBundleScript?: try { + guard case .beginBundleScript(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 336) + }() + case .endBundleScript?: try { + guard case .endBundleScript(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 337) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -8817,13 +8874,14 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Program" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}uuid\0\u{1}code\0\u{1}comments\0\u{1}parent\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}uuid\0\u{1}code\0\u{1}comments\0\u{1}parent\0\u{1}isBundle\0") fileprivate class _StorageClass { var _uuid: Data = Data() var _code: [Fuzzilli_Protobuf_Instruction] = [] var _comments: Dictionary = [:] var _parent: Fuzzilli_Protobuf_Program? = nil + var _isBundle: Bool = false // This property is used as the initial default value for new instances of the type. // The type itself is protecting the reference to its storage via CoW semantics. @@ -8838,6 +8896,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa _code = source._code _comments = source._comments _parent = source._parent + _isBundle = source._isBundle } } @@ -8860,6 +8919,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._code) }() case 3: try { try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap.self, value: &_storage._comments) }() case 4: try { try decoder.decodeSingularMessageField(value: &_storage._parent) }() + case 5: try { try decoder.decodeSingularBoolField(value: &_storage._isBundle) }() default: break } } @@ -8884,6 +8944,9 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa try { if let v = _storage._parent { try visitor.visitSingularMessageField(value: v, fieldNumber: 4) } }() + if _storage._isBundle != false { + try visitor.visitSingularBoolField(value: _storage._isBundle, fieldNumber: 5) + } } try unknownFields.traverse(visitor: &visitor) } @@ -8897,6 +8960,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa if _storage._code != rhs_storage._code {return false} if _storage._comments != rhs_storage._comments {return false} if _storage._parent != rhs_storage._parent {return false} + if _storage._isBundle != rhs_storage._isBundle {return false} return true } if !storagesAreEqual {return false} diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index bdea24d6c..1a7c830c6 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -359,6 +359,8 @@ message Instruction { EndClassComputedGetter endClassComputedGetter = 333; BeginClassComputedSetter beginClassComputedSetter = 334; EndClassComputedSetter endClassComputedSetter = 335; + BeginBundleScript beginBundleScript = 336; + EndBundleScript endBundleScript = 337; } } @@ -367,4 +369,5 @@ message Program { repeated Instruction code = 2; map comments = 3; Program parent = 4; + bool isBundle = 5; } diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift index f17c236ce..c18e2b3e2 100644 --- a/Sources/Fuzzilli/Protobuf/sync.pb.swift +++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift @@ -65,6 +65,8 @@ public struct Fuzzilli_Protobuf_FuzzerState: Sendable { public var isWasmEnabled: Bool = false + public var areBundlesEnabled: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -241,7 +243,7 @@ extension Fuzzilli_Protobuf_LogMessage: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".FuzzerState" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}corpus\0\u{1}evaluatorState\0\u{1}isWasmEnabled\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}corpus\0\u{1}evaluatorState\0\u{1}isWasmEnabled\0\u{1}areBundlesEnabled\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -252,6 +254,7 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M case 1: try { try decoder.decodeSingularBytesField(value: &self.corpus) }() case 2: try { try decoder.decodeSingularBytesField(value: &self.evaluatorState) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.isWasmEnabled) }() + case 4: try { try decoder.decodeSingularBoolField(value: &self.areBundlesEnabled) }() default: break } } @@ -267,6 +270,9 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M if self.isWasmEnabled != false { try visitor.visitSingularBoolField(value: self.isWasmEnabled, fieldNumber: 3) } + if self.areBundlesEnabled != false { + try visitor.visitSingularBoolField(value: self.areBundlesEnabled, fieldNumber: 4) + } try unknownFields.traverse(visitor: &visitor) } @@ -274,6 +280,7 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M if lhs.corpus != rhs.corpus {return false} if lhs.evaluatorState != rhs.evaluatorState {return false} if lhs.isWasmEnabled != rhs.isWasmEnabled {return false} + if lhs.areBundlesEnabled != rhs.areBundlesEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/sync.proto b/Sources/Fuzzilli/Protobuf/sync.proto index 39a18a115..4f3b134ab 100644 --- a/Sources/Fuzzilli/Protobuf/sync.proto +++ b/Sources/Fuzzilli/Protobuf/sync.proto @@ -29,6 +29,7 @@ message FuzzerState { bytes corpus = 1; bytes evaluatorState = 2; bool isWasmEnabled = 3; + bool areBundlesEnabled = 4; } message Statistics { diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 615825f21..ccc1a60c3 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -104,6 +104,7 @@ if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != This can for example be used to remember the target revision that is being fuzzed. --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + --bundle : Generate bundles containing multiple JS scripts and modules """) exit(0) @@ -163,6 +164,7 @@ let argumentRandomization = args.has("--argumentRandomization") let additionalArguments = args["--additionalArguments"] ?? "" let tag = args["--tag"] let enableWasm = args.has("--wasm") +let generateBundle = args.has("--bundle") let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") var timeout: Timeout @@ -441,6 +443,8 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let finalArgs = baseArgs + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) + // TODO(mliedtke): The flag should be controllable via the profile. + + (configuration.generateBundle ? ["--bundle"] : []) return REPRL( executable: jsShellPath, processArguments: finalArgs, @@ -461,7 +465,13 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { }() /// The mutation fuzzer responsible for mutating programs from the corpus and evaluating the outcome. - let disabledMutators = Set(profile.disabledMutators) + var disabledMutators = Set(profile.disabledMutators) + + if configuration.generateBundle { + // TODO(marja): enable combining bundles. + disabledMutators.insert("CombineMutator") + } + var mutators = WeightedList([ (ExplorationMutator(), 3), (CodeGenMutator(), 2), @@ -617,6 +627,7 @@ let mainConfig = Configuration( staticCorpus: staticCorpus, tag: tag, isWasmEnabled: enableWasm, + generateBundle: generateBundle, storagePath: storagePath, corpusGenerationIterations: corpusGenerationIterations, forDifferentialFuzzing: forDifferentialFuzzing, @@ -797,6 +808,7 @@ for i in 1.. Date: Thu, 16 Apr 2026 12:13:08 +0200 Subject: [PATCH 042/223] Improve error messages in cases of invalid code objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I2d86a3970a67ac92c9a2c8690b255b18b8d71bee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210757 Commit-Queue: Matthias Liedtke Reviewed-by: Marja Hölttä --- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 2 +- Sources/Fuzzilli/FuzzIL/Code.swift | 19 +++++++++++++++++-- Sources/Fuzzilli/FuzzIL/Program.swift | 2 +- .../Minimization/InliningReducer.swift | 2 +- .../Minimization/MinimizationHelper.swift | 6 +++++- Sources/Fuzzilli/Minimization/Minimizer.swift | 4 ++-- .../Minimization/ReassignReducer.swift | 2 +- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index ce6edb562..6e6a392b0 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -26,7 +26,7 @@ extension Analyzer { } mutating func analyze(_ code: Code) { - assert(code.isStaticallyValid()) + code.assertIsStaticallyValid() for instr in code { analyze(instr) } diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index 199ec341a..1118a7073 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -148,7 +148,7 @@ public struct Code: Collection { /// Computes the last variable (which will have the highest number) in this code or nil if there are no variables. public func lastVariable() -> Variable? { - assert(isStaticallyValid()) + assertIsStaticallyValid() for instr in instructions.reversed() { if let v = instr.allOutputs.max() { return v @@ -159,7 +159,7 @@ public struct Code: Collection { /// Computes the next free variable in this code. public func nextFreeVariable() -> Variable { - assert(isStaticallyValid()) + assertIsStaticallyValid() if let lastVar = lastVariable() { return Variable(number: lastVar.number + 1) } @@ -321,6 +321,21 @@ public struct Code: Collection { } } + // Helper function for asserting that the Code object is valid. Use this over + // assert(code.isValid()) to get more useful error messages if the assert triggers. + public func assertIsStaticallyValid() { + #if DEBUG + do { + try check() + } catch { + // This assumes that even if the code is invalid, the FuzzILLifter will be able to + // handle it without crashing. If that is not the case, it might be better to not print + // the code at all. + fatalError("Code is invalid: \(error)\n\(FuzzILLifter().lift(self))") + } + #endif + } + public func countIntructionsWith(flags: Instruction.Flags) -> Int { self.filter { instr in instr.flags.contains(flags) diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index f7e4e4b58..7b151998d 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -54,7 +54,7 @@ public final class Program: CustomStringConvertible { /// Constructs a program with the given code. The code must be statically valid. public init(with code: Code) { - assert(code.isStaticallyValid()) + code.assertIsStaticallyValid() self.code = code } diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 94f81e904..f6af53318 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -258,7 +258,7 @@ struct InliningReducer: Reducer { c.renumberVariables() // The code must now be valid. - assert(c.isStaticallyValid()) + c.assertIsStaticallyValid() return c } } diff --git a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift index 80691a669..fa90ab0fe 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift @@ -123,7 +123,11 @@ class MinimizationHelper { ) -> Bool { assert(!self.finalized) assert(numExecutions > 0) - assert(!expectCodeToBeValid || newCode.isStaticallyValid()) + #if DEBUG + if expectCodeToBeValid { + newCode.assertIsStaticallyValid() + } + #endif // Reducers are allowed to nop instructions without verifying whether their outputs are used. // They are also allowed to remove blocks without verifying whether their opened contexts are required. diff --git a/Sources/Fuzzilli/Minimization/Minimizer.swift b/Sources/Fuzzilli/Minimization/Minimizer.swift index 6bdf91ce4..e759f9eb3 100644 --- a/Sources/Fuzzilli/Minimization/Minimizer.swift +++ b/Sources/Fuzzilli/Minimization/Minimizer.swift @@ -118,7 +118,7 @@ public class Minimizer: ComponentBase { assert( helper.code.countIntructionsWith(flags: .notRemovable) >= helper.numKeptInstructions) - assert(helper.code.isStaticallyValid()) + helper.code.assertIsStaticallyValid() } iterations += 1 guard iterations < 100 else { @@ -145,7 +145,7 @@ public class Minimizer: ComponentBase { postProcessor.process(with: helper) } - assert(helper.code.isStaticallyValid()) + helper.code.assertIsStaticallyValid() assert(!helper.code.contains(where: { $0.isNop })) return helper.finalize() diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index e473f28c1..8226089a5 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -86,7 +86,7 @@ struct ReassignmentReducer: Reducer { } } - assert(newCode.isStaticallyValid()) + newCode.assertIsStaticallyValid() if didChangeCode { helper.testAndCommit(newCode) } From fc8ac822074e92d4868ae1af1111d24cf3eedd18 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 16 Apr 2026 17:20:44 +0200 Subject: [PATCH 043/223] [test] Skip flaky test case for --bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I04428445c2feae6749a74f71a63ce4e3363f3f3a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211138 Reviewed-by: Marja Hölttä Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Tests/FuzzilliTests/ProgramBuilderTest.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 76c604c0c..14a2bb9f8 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3291,7 +3291,10 @@ class ProgramBuilderTests: XCTestCase { } } - func testThatBundleGeneratorsAreBuildableFromBundle() { + func testThatBundleGeneratorsAreBuildableFromBundle() throws { + // TODO(mliedtke,marja): Investigate how we can make the code generator scheduling more + // reliable. + if true { throw XCTSkip("Test case is flaky") } let config = Configuration(generateBundle: true) let fuzzer = makeMockFuzzer(config: config) let tries: Int = 10 @@ -3309,7 +3312,7 @@ class ProgramBuilderTests: XCTestCase { if generatedInstructions == 0 { failures[generator.name, default: 0] += 1 } - XCTAssertLessThan(syntheticGenerator.parts.count, 10) + XCTAssertLessThan(syntheticGenerator.parts.count, 10, "for \(generator.name)") } else { XCTFail( "Unable to generate synthetic CodeGenerator for \(generator.name) from a bundle." From 2cfe7c3d61bee425dc32810579bf46609c99384a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 16 Apr 2026 14:27:25 +0200 Subject: [PATCH 044/223] [wasm] Make it easier to generate any.convert_extern Change-Id: Ifa582d369584dc6ba774112f5f7dba6f1b7663fb Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210758 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift | 5 +++-- Tests/FuzzilliTests/ProgramBuilderTest.swift | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index eb5c1c514..65275e1db 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -344,7 +344,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(pawkra): add shared variant. CodeGenerator( - "WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32) + "WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32), + produces: [.wasmI31Ref()] ) { b, value in b.currentWasmModule.currentWasmFunction.wasmRefI31(value, shared: false) }, @@ -367,7 +368,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(pawkra): add shared variant. CodeGenerator( "WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), - inputs: .required(.wasmAnyRef()) + inputs: .required(.wasmAnyRef()), produces: [.wasmExternRef()] ) { b, ref in b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) }, diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 14a2bb9f8..6ed19b068 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3253,6 +3253,8 @@ class ProgramBuilderTests: XCTestCase { test("WasmArrayGetGenerator", expectAny: WasmArrayGet.self, requiresTypes: true) test("WasmStructGetGenerator", expectAny: WasmStructGet.self, requiresTypes: true) test("WasmThrowRefGenerator", expectAny: WasmThrowRef.self) + test("WasmExternConvertAnyGenerator", expectAny: WasmExternConvertAny.self) + test("WasmAnyConvertExternGenerator", expectAny: WasmAnyConvertExtern.self) } func testThatGeneratorsExistAndAreBuildableFromJs() { From 79f9aa85045ebcb5325f2637a3d9d2766363aab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Fri, 17 Apr 2026 08:09:24 +0200 Subject: [PATCH 045/223] [js, bundles] Don't warn about BundleScriptGenerator if we're not generating bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 342521422 Change-Id: I5b40c6c2e97ed1e52a48d987d96cb00bbbdf82c9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211116 Auto-Submit: Marja Hölttä Reviewed-by: Matthias Liedtke Commit-Queue: Marja Hölttä --- Sources/Fuzzilli/Base/ContextGraph.swift | 15 ++++++++++----- Sources/Fuzzilli/Fuzzer.swift | 6 ++++-- Tests/FuzzilliTests/ContextGraphTest.swift | 6 +++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Sources/Fuzzilli/Base/ContextGraph.swift b/Sources/Fuzzilli/Base/ContextGraph.swift index 722801e64..6d706e0cb 100644 --- a/Sources/Fuzzilli/Base/ContextGraph.swift +++ b/Sources/Fuzzilli/Base/ContextGraph.swift @@ -54,9 +54,11 @@ public class ContextGraph { // This is the Graph, each pair of from and to, maps to a `GeneratorEdge`. var edges: [EdgeKey: GeneratorEdge] = [:] - public init(for generators: WeightedList, withLogger logger: Logger) { + public init( + for generators: WeightedList, isBundle: Bool, withLogger logger: Logger + ) { assertBasicConsistency(in: generators) - warnOfSuspiciousContexts(in: generators, withLogger: logger) + warnOfSuspiciousContexts(in: generators, isBundle: isBundle, withLogger: logger) // One can still try to build in a context that doesn't have generators, this will be caught in the build function, if we fail to find any suitable generator. // Otherwise we could assert here that the sets are equal. @@ -96,10 +98,10 @@ public class ContextGraph { } private func warnOfSuspiciousContexts( - in generators: WeightedList, withLogger logger: Logger + in generators: WeightedList, isBundle: Bool, withLogger logger: Logger ) { - // Technically we don't need any generator to emit the .javascript context, as this is provided by the toplevel. - var providedContexts = Set([.javascript]) + // Technically we don't need any generator to emit the .bundle or .javascript context, as they are provided by the toplevel. + var providedContexts = Set([isBundle ? .bundle : .javascript]) var requiredContexts = Set() for generator in generators { @@ -112,6 +114,9 @@ public class ContextGraph { for generator in generators { // Now check which generators don't have providers if !providedContexts.contains(generator.requiredContext) { + if !isBundle && generator.requiredContext == .bundle { + continue + } logger.warning( "Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context." ) diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 7a2d93ab5..6ab97c135 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -210,7 +210,8 @@ public class Fuzzer { self.referenceRunner = referenceScriptRunner self.minimizer = minimizer self.logger = Logger(withLabel: "Fuzzer") - self.contextGraph = ContextGraph(for: codeGenerators, withLogger: self.logger) + self.contextGraph = ContextGraph( + for: codeGenerators, isBundle: configuration.generateBundle, withLogger: self.logger) self.corpusGenerationEngine = GenerativeEngine(generateBundle: configuration.generateBundle) // Pass-through any postprocessor to the generative engine. @@ -252,7 +253,8 @@ public class Fuzzer { fatalError("Code generators must contain at least one value generator") } // This builds a graph that we need later for scheduling generators. - self.contextGraph = ContextGraph(for: generators, withLogger: self.logger) + self.contextGraph = ContextGraph( + for: generators, isBundle: self.config.generateBundle, withLogger: self.logger) self.codeGenerators = generators } diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index 60bec3eec..97aec8fa2 100644 --- a/Tests/FuzzilliTests/ContextGraphTest.swift +++ b/Tests/FuzzilliTests/ContextGraphTest.swift @@ -20,7 +20,7 @@ class ContextGraphTests: XCTestCase { func testReachabilityCalculationForJS() { let fuzzer = makeMockFuzzer() let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: false, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .javascript)) @@ -39,7 +39,7 @@ class ContextGraphTests: XCTestCase { let config = Configuration(generateBundle: true) let fuzzer = makeMockFuzzer(config: config) let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: true, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .bundle)) @@ -55,7 +55,7 @@ class ContextGraphTests: XCTestCase { func testSubsetReachabilityCalculation() { let fuzzer = makeMockFuzzer() let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: false, withLogger: Logger(withLabel: "Test")) let reachableContextsWasm = Set(contextGraph.getReachableContexts(from: .wasm)) let reachableContextsWasm2 = Set(contextGraph.getReachableContexts(from: .wasm)) From d5a995ec7f3a51d867f6d88c6d0bcb39bbd73cb8 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 17 Apr 2026 11:30:25 +0000 Subject: [PATCH 046/223] Rename wasm-related labels This CL renames wasm-related labels to better distinguish them from js-related labels, which we're currently adding. Change-Id: I9682b4a30e18c0d4f5704a49a2890c4647def159 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210958 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 12 +++++----- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 14 +++++------ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 10 ++++---- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 24 +++++++++---------- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 2 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 6 ++--- Tests/FuzzilliTests/WasmTests.swift | 16 ++++++------- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 44cc8f64a..8e2dc2443 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4932,7 +4932,7 @@ public class ProgramBuilder { #if DEBUG var argIndex = signature.parameterTypes.count let assertLabelTypeData: (ILType) -> Void = { labelType in - assert(labelType.Is(.anyLabel)) + assert(labelType.Is(.anyWasmLabel)) assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef())) } for catchKind in catches { @@ -4944,14 +4944,14 @@ public class ProgramBuilder { argIndex += 2 case .NoRef: assert(b.type(of: args[argIndex]).Is(.object(ofGroup: "WasmTag"))) - assert(b.type(of: args[argIndex + 1]).Is(.anyLabel)) + assert(b.type(of: args[argIndex + 1]).Is(.anyWasmLabel)) argIndex += 2 case .AllRef: let labelType = b.type(of: args[argIndex]) assertLabelTypeData(labelType) argIndex += 1 case .AllNoRef: - assert(b.type(of: args[argIndex]).Is(.anyLabel)) + assert(b.type(of: args[argIndex]).Is(.anyWasmLabel)) argIndex += 1 } } @@ -5087,8 +5087,8 @@ public class ProgramBuilder { b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef()]) } - public func wasmBuildLegacyRethrow(_ exceptionLabel: Variable) { - b.emit(WasmRethrow(), withInputs: [exceptionLabel], types: [.exceptionLabel]) + public func wasmBuildLegacyRethrow(_ wasmExceptionLabel: Variable) { + b.emit(WasmRethrow(), withInputs: [wasmExceptionLabel], types: [.wasmExceptionLabel]) } public func wasmBuildLegacyTryDelegate( @@ -5120,7 +5120,7 @@ public class ProgramBuilder { b.emit( WasmEndTryDelegate(outputCount: signature.outputTypes.count), withInputs: [signatureDef, delegate] + results, - types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes + types: [.wasmTypeDef(), .anyWasmLabel] + signature.outputTypes ).outputs) } diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 65275e1db..e0676a9fc 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1609,7 +1609,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmLegacyTryDelegateGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel) + inputs: .required(.anyWasmLabel) ) { b, label in let function = b.currentWasmModule.currentWasmFunction // Choose a few random wasm values as arguments if available. @@ -1734,7 +1734,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmLegacyRethrowGenerator", inContext: .single(.wasmFunction), - inputs: .required(.exceptionLabel) + inputs: .required(.wasmExceptionLabel) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction function.wasmBuildLegacyRethrow(exception) @@ -1800,7 +1800,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmBranchGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel) + inputs: .required(.anyWasmLabel) ) { b, label in let function = b.currentWasmModule.currentWasmFunction let args = b.type(of: label).wasmLabelType!.parameters.map( @@ -1810,7 +1810,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmBranchIfGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel, .wasmi32) + inputs: .required(.anyWasmLabel, .wasmi32) ) { b, label, conditionVar in let function = b.currentWasmModule.currentWasmFunction let args = b.type(of: label).wasmLabelType!.parameters.map( @@ -1828,7 +1828,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // Choose parameter types for the br_table. If we can find an existing label, just use that // label types as it allows use to reuse existing (and therefore more interesting) blocks. let parameterTypes = - if let label = b.randomVariable(ofType: .anyLabel) { + if let label = b.randomVariable(ofType: .anyWasmLabel) { b.type(of: label).wasmLabelType!.parameters } else { b.randomWasmBlockOutputTypes(upTo: 3) @@ -1841,7 +1841,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.emit(WasmBeginBlock(parameterCount: 0), withInputs: [signatureDef]) } let labels = (0...valueCount).map { _ in - b.randomVariable(ofType: .label(parameterTypes))! + b.randomVariable(ofType: .wasmLabel(parameterTypes))! } let args = parameterTypes.map(function.findOrGenerateWasmVar) function.wasmBranchTable(on: value, labels: labels, args: args) @@ -1897,7 +1897,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // same parameter types could also be mapped to the same block.) let labels = signatureDefs.map { signatureDef in b.randomVariable( - ofType: .label( + ofType: .wasmLabel( b.type(of: signatureDef).wasmFunctionSignatureDefSignature.outputTypes))! } let catches = zip(tags, withExnRef).map { diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 078e34378..c7992206c 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -710,7 +710,7 @@ public struct JSTyper: Analyzer { // Helper function to type a "regular" wasm begin block (block, if, try). mutating func wasmTypeBeginBlock(_ instr: Instruction, _ signature: WasmSignature) { - setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.outputTypes)) for (innerOutput, paramType) in zip( instr.innerOutputs.dropFirst(), signature.parameterTypes) { @@ -971,7 +971,7 @@ public struct JSTyper: Analyzer { // of the block, not the result types (because a branch to a loop label jumps to the // beginning of the loop block instead of the end.) let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.innerOutputs.first!, to: .label(signature.parameterTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.parameterTypes)) for (innerOutput, paramType) in zip( instr.innerOutputs.dropFirst(), signature.parameterTypes) { @@ -999,11 +999,11 @@ public struct JSTyper: Analyzer { wasmTypeBeginBlock(instr, signature) case .wasmBeginCatchAll(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.outputTypes)) case .wasmBeginCatch(_): let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature // Type the label (used for branch instructions). - setType(of: instr.innerOutput(0), to: .label(blockSignature.outputTypes)) + setType(of: instr.innerOutput(0), to: .wasmLabel(blockSignature.outputTypes)) // Register the tag (Wasm exception) in the dynamicObjectGroupManager as being used // by this Wasm module. let tag = instr.input(1) @@ -1014,7 +1014,7 @@ public struct JSTyper: Analyzer { // The second inner output is the exception label which is used for rethrowing the // exception with the legacy exception handling proposal. (This is similar to the // exnref in the standard exception handling spec.) - setType(of: instr.innerOutput(1), to: .exceptionLabel) + setType(of: instr.innerOutput(1), to: .wasmExceptionLabel) // Type the tag parameters based on the tag's signature definition. // This guarantees that the inner outputs are properly typed, even if a mutator // changed the tag variable to something that's not typed as a Wasm tag anymore. diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index e546fae6d..a19b294c1 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -222,21 +222,21 @@ public struct ILType: Hashable { // Internal types // This type is used to indicate block labels in wasm. - public static func label(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { + public static func wasmLabel(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { return ILType( - definiteType: .label, + definiteType: .wasmLabel, ext: TypeExtension( group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) } - public static let anyLabel: ILType = ILType( - definiteType: .label, + public static let anyWasmLabel: ILType = ILType( + definiteType: .wasmLabel, ext: TypeExtension( group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) /// A label that allows rethrowing the caught exception of a catch block. - public static let exceptionLabel: ILType = ILType(definiteType: .exceptionLabel) + public static let wasmExceptionLabel: ILType = ILType(definiteType: .wasmExceptionLabel) public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) -> ILType @@ -1245,11 +1245,11 @@ extension ILType: CustomStringConvertible { return ".wasmPackedI8" case .wasmPackedI16: return ".wasmPackedI16" - case .label: + case .wasmLabel: if let labelType = self.wasmLabelType { - return ".label(\(labelType.parameters))" + return ".wasmLabel(\(labelType.parameters))" } - return ".label" + return ".wasmLabel" case .wasmRef: guard let refType = self.wasmReferenceType else { return ".wasmGenericRef" @@ -1276,8 +1276,8 @@ extension ILType: CustomStringConvertible { return ".wasmTypeDef(\(desc))" } return ".wasmTypeDef(nil)" - case .exceptionLabel: - return ".exceptionLabel" + case .wasmExceptionLabel: + return ".wasmExceptionLabel" case .wasmDataSegment: return ".wasmDataSegment" case .wasmElementSegment: @@ -1336,11 +1336,11 @@ struct BaseType: OptionSet, Hashable { static let wasmf64 = BaseType(rawValue: 1 << 15) // These are wasm internal types, these are never lifted as such and are only used to glue together dataflow in wasm. - static let label = BaseType(rawValue: 1 << 16) + static let wasmLabel = BaseType(rawValue: 1 << 16) // Any catch block exposes such a label now to rethrow the exception caught by that catch. // Note that in wasm the label is actually the try block's label but as rethrows are only possible inside a catch // block, semantically having a label on the catch makes more sense. - static let exceptionLabel = BaseType(rawValue: 1 << 17) + static let wasmExceptionLabel = BaseType(rawValue: 1 << 17) // This is a reference to a table, which can be passed around to table instructions // The lifter will resolve this to the proper index when lifting. static let wasmSimd128 = BaseType(rawValue: 1 << 18) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index ef8e416b6..113cd8e3f 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1452,7 +1452,7 @@ final class WasmBeginCatch: WasmOperation { // branching as well as for rethrowing the exception. However, rethrows may only use labels // from catch blocks and branches may use any label but need to be very precise on the type // of the label parameters, so typing the label would require different subtyping based on - // the usage. For now, we just emit a label for branching and the ".exceptionLabel" for + // the usage. For now, we just emit a label for branching and the ".wasmExceptionLabel" for // rethrows. super.init( // Inputs: The block signature, the tag, the tag signature, and the outputs of the preceding try or catch diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index a5a0232f3..e9e35cc1c 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1408,7 +1408,7 @@ public class WasmLifter { for input in instr.inputs { // Skip "internal" inputs, i.e. ones that don't map to a slot, such as .label variables let inputType = typer.type(of: input) - if inputType.Is(.anyLabel) || inputType.Is(.exceptionLabel) { + if inputType.Is(.anyWasmLabel) || inputType.Is(.wasmExceptionLabel) { continue } @@ -1444,7 +1444,7 @@ public class WasmLifter { // If we have an output, make sure we store it on the stack as this is a "complex" instruction, i.e. has inputs and outputs. if instr.numOutputs > 0 { - assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyLabel) }) + assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyWasmLabel) }) for output in instr.outputs.reversed() { // Also spill the instruction currentFunction!.spillLocal(forVariable: output) @@ -1460,7 +1460,7 @@ public class WasmLifter { // As the parameters are pushed "in order" to the stack, they need to be popped in reverse order. for innerOutput in instr.innerOutputs.reversed() { let t = typer.type(of: innerOutput) - if !t.Is(.anyLabel) && !t.Is(.exceptionLabel) { + if !t.Is(.anyWasmLabel) && !t.Is(.wasmExceptionLabel) { currentFunction!.spillLocal(forVariable: innerOutput) } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 5006e0c91..d18ecef71 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -412,7 +412,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let ctr = function.consti32(10) function.wasmBuildLoop(with: [] => [], args: []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let result = function.wasmi32BinOp(ctr, function.consti32(1), binOpKind: .Sub) function.wasmReassign(variable: ctr, to: result) // The backedge, loop if we are not at zero yet. @@ -3742,7 +3742,7 @@ class WasmFoundationTests: XCTestCase { let one = function.consti32(1) function.wasmBuildLoop(with: [] => [], args: []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let result = function.wasmi32BinOp(ctr, one, binOpKind: .Add) let varUpdate = function.wasmi64BinOp( variable, function.consti64(2), binOpKind: .Add) @@ -4023,7 +4023,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) function.wasmReturn(function.consti64(42)) } return [function.consti64(-1)] @@ -4056,7 +4056,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) // Manually set the availableTypes here for testing. let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( b.type(of: functionA).signature!, availableTypes: WeightedList([])) @@ -4102,7 +4102,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid( body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( b.type(of: functionA).signature!, availableTypes: WeightedList([])) function.wasmJsCall( @@ -4167,7 +4167,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid( body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) function.WasmBuildThrow( tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) function.wasmUnreachable() @@ -4221,7 +4221,7 @@ class WasmFoundationTests: XCTestCase { catchClauses: [ ( tag: tag, - body: { catchLabel, exceptionLabel, args in + body: { catchLabel, wasmExceptionLabel, args in function.wasmBranch(to: catchLabel) } ) @@ -4374,7 +4374,7 @@ class WasmFoundationTests: XCTestCase { signature: signature, signatureDef: signatureDef, args: [argI64, argI32], body: { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) XCTAssertEqual(b.type(of: args[0]), .wasmi64) XCTAssertEqual(b.type(of: args[1]), .wasmi32) function.WasmBuildThrow(tag: tag, inputs: args) From afc490749f693c2a5a4dbdde8330231719c51021 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 17 Apr 2026 11:44:16 +0000 Subject: [PATCH 047/223] Have Instruction ctor use .empty flags by default This cleans up the code a bit. Change-Id: I12c467936fbfaceec025922aee407e00ce82c545 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211219 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/Compiler/Compiler.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 14 +++++++------- Sources/Fuzzilli/Minimization/BlockReducer.swift | 10 +++++----- .../Minimization/InstructionSimplifier.swift | 8 ++++---- Sources/Fuzzilli/Minimization/LoopSimplifier.swift | 14 +++++++------- .../Fuzzilli/Minimization/MinimizationHelper.swift | 3 +-- .../Fuzzilli/Minimization/ReassignReducer.swift | 2 +- .../Minimization/WasmTypeGroupReducer.swift | 2 +- Sources/Fuzzilli/Mutators/InputMutator.swift | 2 +- Sources/Fuzzilli/Mutators/OperationMutator.swift | 4 ++-- Tests/FuzzilliTests/LifterTest.swift | 2 +- 12 files changed, 32 insertions(+), 33 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 8e2dc2443..2ca4a0d0b 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2657,7 +2657,7 @@ public class ProgramBuilder { } } - return internalAppend(Instruction(op, inouts: inouts, flags: .empty)) + return internalAppend(Instruction(op, inouts: inouts)) } @discardableResult diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 1ecdf89e6..f5168eacd 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -1470,7 +1470,7 @@ public class JavaScriptCompiler { let outputs = (0..( - _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags + _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags = .empty ) where Variables.Element == Variable { assert(op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count) self.op = op @@ -263,33 +263,33 @@ public struct Instruction { public init(_ op: Operation, output: Variable) { assert(op.numInputs == 0 && op.numOutputs == 1 && op.numInnerOutputs == 0) - self.init(op, inouts: [output], flags: .empty) + self.init(op, inouts: [output]) } public init(_ op: Operation, output: Variable, inputs: [Variable]) { assert(op.numOutputs == 1) assert(op.numInnerOutputs == 0) assert(op.numInputs == inputs.count) - self.init(op, inouts: inputs + [output], flags: .empty) + self.init(op, inouts: inputs + [output]) } public init(_ op: Operation, inputs: [Variable]) { assert(op.numOutputs + op.numInnerOutputs == 0) assert(op.numInputs == inputs.count) - self.init(op, inouts: inputs, flags: .empty) + self.init(op, inouts: inputs) } public init(_ op: Operation, innerOutput: Variable) { assert(op.numInnerOutputs == 1) assert(op.numOutputs == 0) assert(op.numInputs == 0) - self.init(op, inouts: [innerOutput], flags: .empty) + self.init(op, inouts: [innerOutput]) } public init(_ op: Operation) { assert(op.numOutputs + op.numInnerOutputs == 0) assert(op.numInputs == 0) - self.init(op, inouts: [], flags: .empty) + self.init(op, inouts: []) } /// Flags associated with an Instruction. @@ -2812,7 +2812,7 @@ extension Instruction: ProtobufConvertible { opCache?.add(op) - self.init(op, inouts: inouts, flags: .empty) + self.init(op, inouts: inouts) } init(from proto: ProtobufType) throws { diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 5af1d5e3e..1de029dcc 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -272,7 +272,7 @@ struct BlockReducer: Reducer { replacements.append( ( ifBlock.head, - Instruction(invertedIf, inouts: helper.code[ifBlock.head].inouts, flags: .empty) + Instruction(invertedIf, inouts: helper.code[ifBlock.head].inouts) )) // The rest of the if body is nopped ... for instr in helper.code.body(of: ifBlock) { @@ -354,7 +354,7 @@ struct BlockReducer: Reducer { continue // Skip the block begin and end. } let newInouts = instr.inouts.map({ varReplacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() return helper.testAndCommit(newCode) @@ -503,7 +503,7 @@ struct BlockReducer: Reducer { // of the original WasmBeginElse block, so that users of them are rewired correctly. let inouts = helper.code[ifBlock.head].inputs + helper.code[elseBlock.head].allOutputs replacements.append( - (ifBlock.head, Instruction(invertedIf, inouts: inouts, flags: .empty))) + (ifBlock.head, Instruction(invertedIf, inouts: inouts))) // The rest of the if body is nopped ... for instr in helper.code.body(of: ifBlock) { replacements.append((instr.index, helper.nop(for: instr))) @@ -549,7 +549,7 @@ struct BlockReducer: Reducer { continue // Skip the WasmBeginIf and the else block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() if helper.testAndCommit(newCode) { @@ -579,7 +579,7 @@ struct BlockReducer: Reducer { continue // Skip the WasmBeginIf and the if true block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() if helper.testAndCommit(newCode) { diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 2126359d7..cc4c8b79a 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -32,7 +32,7 @@ struct InstructionSimplifier: Reducer { let functionName = (begin as? BeginAnyNamedFunction)?.functionName ?? nil let newBegin = Instruction( BeginPlainFunction(parameters: begin.parameters, functionName: functionName), - inouts: helper.code[group.head].inouts, flags: .empty) + inouts: helper.code[group.head].inouts) let newEnd = Instruction(EndPlainFunction()) // The resulting code may be invalid as we may be changing the context inside the body (e.g. turning an async function into a plain one). @@ -61,7 +61,7 @@ struct InstructionSimplifier: Reducer { if let op = newOp { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(op, inouts: instr.inouts, flags: .empty)) + with: Instruction(op, inouts: instr.inouts)) } } } @@ -100,7 +100,7 @@ struct InstructionSimplifier: Reducer { if let op = newOp { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(op, inouts: instr.inouts, flags: .empty)) + with: Instruction(op, inouts: instr.inouts)) } } } @@ -114,7 +114,7 @@ struct InstructionSimplifier: Reducer { if newOp !== op { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) + with: Instruction(newOp, inouts: instr.inouts)) } } } diff --git a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index edf76df0c..6acce260b 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -101,14 +101,14 @@ struct LoopSimplifier: Reducer { newCode.append( Instruction( BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), - inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) + inouts: needLoopVariable ? [loopVar!] : [])) // Append condition, body, and afterthought code var replacements = [Variable: Variable]( uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: conditionBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } let bodyBlock = group.block(3) @@ -117,7 +117,7 @@ struct LoopSimplifier: Reducer { uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: bodyBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } let afterthoughtBlock = group.block(2) @@ -128,7 +128,7 @@ struct LoopSimplifier: Reducer { })) for instr in helper.code.body(of: afterthoughtBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } // Append loop footer @@ -244,7 +244,7 @@ struct LoopSimplifier: Reducer { if originalLoopHeader.exposesLoopCounter { replacement = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: helper.code[group.head].inouts, flags: .empty) + inouts: helper.code[group.head].inouts) } else { replacement = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) @@ -267,7 +267,7 @@ struct LoopSimplifier: Reducer { if newCode[headerIndex].numInnerOutputs > 0 { newCode[headerIndex] = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: newCode[headerIndex].inouts, flags: .empty) + inouts: newCode[headerIndex].inouts) } else { newCode[headerIndex] = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) @@ -370,7 +370,7 @@ struct LoopSimplifier: Reducer { for instr in helper.code[innerHead.. Instruction { // We must preserve outputs here to keep variable number contiguous. return Instruction( - Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, - flags: .empty) + Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs) } } diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index 8226089a5..c69cb0128 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -82,7 +82,7 @@ struct ReassignmentReducer: Reducer { } else { let inouts = instr.inouts.map({ reassignedVariables[$0] ?? $0 }) if inouts[...] != instr.inouts { didChangeCode = true } - newCode.append(Instruction(instr.op, inouts: inouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: inouts)) } } diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 50f2c5eac..aeeaf7b37 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -75,7 +75,7 @@ struct WasmTypeGroupReducer: Reducer { let newInouts = keptInoutsMap.map { $0.0 } + keptInoutsMap.map { $0.1 } endTypeGroupReplacements[instr.index] = Instruction( - WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts, flags: .empty) + WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts) } if toRemove.isEmpty { diff --git a/Sources/Fuzzilli/Mutators/InputMutator.swift b/Sources/Fuzzilli/Mutators/InputMutator.swift index 01c214a89..1fdcee1ed 100644 --- a/Sources/Fuzzilli/Mutators/InputMutator.swift +++ b/Sources/Fuzzilli/Mutators/InputMutator.swift @@ -91,7 +91,7 @@ public class InputMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - b.append(Instruction(instr.op, inouts: inouts, flags: .empty)) + b.append(Instruction(instr.op, inouts: inouts)) } } } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 613b68e1a..8f24ce7d3 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -848,7 +848,7 @@ public class OperationMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - return Instruction(newOp, inouts: instr.inouts, flags: .empty) + return Instruction(newOp, inouts: instr.inouts) } private func extendVariadicOperation(_ instr: Instruction, _ b: ProgramBuilder) -> Instruction { @@ -945,7 +945,7 @@ public class OperationMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - return Instruction(newOp, inouts: inouts, flags: .empty) + return Instruction(newOp, inouts: inouts) } private func replaceRandomElement( diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 1869265d4..03b73e48d 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3990,7 +3990,7 @@ class LifterTests: XCTestCase { var newInouts = oldInstr.inouts // This is the mutation newInouts[1] = f - let instr = Instruction(oldInstr.op, inouts: newInouts, flags: .empty) + let instr = Instruction(oldInstr.op, inouts: newInouts) // Append the mutated instruction now. b.append(instr) // Adopt the rest of the Program. From f5a9ce1406bb7394d046a8904acfe646082d791a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Sun, 19 Apr 2026 20:00:08 +0200 Subject: [PATCH 048/223] [compiler] Fix crash in import of huge numeric literal Don't crash on "delete a[numeric_literal]" for cases where numeric_literal is outside of the Int64 range. Change-Id: Id844f50fbcf2c00e3242094472a5c46163daa092 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9218736 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Compiler/Compiler.swift | 5 +++-- Tests/FuzzilliTests/CompilerTests/large_index_delete.js | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/large_index_delete.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index f5168eacd..6d2fa4d1e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -1375,9 +1375,10 @@ public class JavaScriptCompiler { let propertyExpr = propertyExpression.expression let property = try compileExpression(propertyExpression) - if case .numberLiteral(let numberLiteral) = propertyExpr { + if case .numberLiteral(let numberLiteral) = propertyExpr, + let index = Int64(exactly: numberLiteral.value) + { // Delete an element (e.g., delete arr[42]) - let index = Int64(numberLiteral.value) let instr = emit( DeleteElement(index: index, isGuarded: isGuarded), withInputs: [obj] diff --git a/Tests/FuzzilliTests/CompilerTests/large_index_delete.js b/Tests/FuzzilliTests/CompilerTests/large_index_delete.js new file mode 100644 index 000000000..a98e96082 --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/large_index_delete.js @@ -0,0 +1,5 @@ +if (typeof output === 'undefined') output = console.log; + +const a = [1, 2, 3]; +output(delete a[9223372036854775808]); +output(a); From 1e40d0d26882d42e4cca98779af5cb0870c61867 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 20 Apr 2026 11:20:07 +0200 Subject: [PATCH 049/223] [test] Improve error message in case of failing test There is some failure on the GitHub workflow and I have no idea what's exactly going wrong if the only output is "Could not execute script". Change-Id: Iba8ac6adb87295e0d3eb364b9431f4488f42b45d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9220436 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke --- .github/workflows/swift.yml | 2 +- Tests/FuzzilliTests/WasmTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index bc70a382b..4e98a8afd 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -48,4 +48,4 @@ jobs: - name: Install d8 run: jsvu --os=default --engines=v8 - name: Run tests with d8 - run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -c ${{ matrix.kind }} -v + run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -c ${{ matrix.kind }} diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index d18ecef71..ddfbd6ecf 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -22,7 +22,7 @@ func testExecuteScript(program: String, runner: JavaScriptExecutor) -> JavaScrip do { result = try runner.executeScript(program) } catch { - fatalError("Could not execute Script") + fatalError("Could not execute script: \(error)") } return result } From 4df269fdb6ecc56d3d383757e6df463bc1c8a7a0 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Mon, 20 Apr 2026 11:12:27 +0000 Subject: [PATCH 050/223] Add support for labels, continue-to-lbl, break-to-lbl to generated loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds a label to each generated loop, which is accessible in its scope via `innerOutputs.last`. When generating `break` or `continue` statements, with a probability of 20%, one of the loop labels that are currently in scope are selected as the target. A label is added to each loop and increments the variable counter of the program, but it’s only emitted if the label is referenced. In subsequent CLs, I plan to add: - label support for block, switch, if/else statements - parsing support for such labels Change-Id: I79606416e91525a42d5bcd91583f72c904a1dc80 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206398 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 97 +++++-- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 6 +- Sources/Fuzzilli/Compiler/Compiler.swift | 5 +- Sources/Fuzzilli/FuzzIL/Code.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 6 +- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 20 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 38 ++- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 10 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 43 +-- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 76 ++++-- .../Minimization/LoopSimplifier.swift | 107 +++++--- .../Fuzzilli/Profiles/V8CommonProfile.swift | 2 +- Tests/FuzzilliTests/LabelTests.swift | 253 ++++++++++++++++++ Tests/FuzzilliTests/LifterTest.swift | 36 +-- Tests/FuzzilliTests/ProgramBuilderTest.swift | 10 +- 15 files changed, 567 insertions(+), 144 deletions(-) create mode 100644 Tests/FuzzilliTests/LabelTests.swift diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 2ca4a0d0b..970bb474e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2640,7 +2640,7 @@ public class ProgramBuilder { inouts.append(nextVariable()) } - // For WasmOperations, we can assert here that the input types are correct. + // We can assert here that the input types are correct. if let expectedTypes = types { // TODO: try to make sure that mutations don't change the assumptions while ProgramBuilding. if inputs.count != expectedTypes.count { @@ -3924,26 +3924,34 @@ public class ProgramBuilder { emit(SwitchBreak()) } - public func buildWhileLoop(_ header: () -> Variable, _ body: () -> Void) { + public func buildWhileLoop(_ header: () -> Variable, _ body: (Variable) -> Void) { emit(BeginWhileLoopHeader()) let cond = header() - emit(BeginWhileLoopBody(), withInputs: [cond]) - body() + let label = emit(BeginWhileLoopBody(), withInputs: [cond]).innerOutput + body(label) emit(EndWhileLoop()) } - public func buildDoWhileLoop(do body: () -> Void, while header: () -> Variable) { - emit(BeginDoWhileLoopBody()) - body() + public func buildWhileLoop(_ header: () -> Variable, _ body: () -> Void) { + buildWhileLoop(header) { _ in body() } + } + + public func buildDoWhileLoop(do body: (Variable) -> Void, while header: () -> Variable) { + let label = emit(BeginDoWhileLoopBody()).innerOutput + body(label) emit(BeginDoWhileLoopHeader()) let cond = header() emit(EndDoWhileLoop(), withInputs: [cond]) } + public func buildDoWhileLoop(do body: () -> Void, while header: () -> Variable) { + buildDoWhileLoop(do: { _ in body() }, while: header) + } + // Build a simple for loop that declares one loop variable. public func buildForLoop( i initializer: () -> Variable, _ cond: (Variable) -> Variable, - _ afterthought: (Variable) -> Void, _ body: (Variable) -> Void + _ afterthought: (Variable) -> Void, _ body: (Variable, Variable) -> Void ) { emit(BeginForLoopInitializer()) let initialValue = initializer() @@ -3953,11 +3961,18 @@ public class ProgramBuilder { loopVar = emit(BeginForLoopAfterthought(numLoopVariables: 1), withInputs: [cond]).innerOutput afterthought(loopVar) - loopVar = emit(BeginForLoopBody(numLoopVariables: 1)).innerOutput - body(loopVar) + let instr = emit(BeginForLoopBody(numLoopVariables: 1)) + body(instr.innerOutput(0), instr.innerOutput(1)) emit(EndForLoop()) } + public func buildForLoop( + i initializer: () -> Variable, _ cond: (Variable) -> Variable, + _ afterthought: (Variable) -> Void, _ body: (Variable) -> Void + ) { + buildForLoop(i: initializer, cond, afterthought) { i, _ in body(i) } + } + // Build arbitrarily complex for loops without any loop variables. public func buildForLoop( _ initializer: (() -> Void)? = nil, _ cond: (() -> Variable)? = nil, @@ -3991,51 +4006,83 @@ public class ProgramBuilder { ).innerOutputs afterthought?(Array(loopVars)) loopVars = emit(BeginForLoopBody(numLoopVariables: initialValues.count)).innerOutputs + .dropLast() body(Array(loopVars)) emit(EndForLoop()) } - public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> Void) { - let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput - body(i) + public func buildForInLoop(_ obj: Variable, _ body: (Variable, Variable) -> Void) { + let instr = emit(BeginForInLoop(), withInputs: [obj]) + body(instr.innerOutput(0), instr.innerOutput(1)) emit(EndForInLoop()) } - public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> Void) { - let i = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput - body(i) + public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> Void) { + buildForInLoop(obj) { i, _ in body(i) } + } + + public func buildForOfLoop(_ obj: Variable, _ body: (Variable, Variable) -> Void) { + let instr = emit(BeginForOfLoop(), withInputs: [obj]) + body(instr.innerOutput(0), instr.innerOutput(1)) emit(EndForOfLoop()) } + public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> Void) { + buildForOfLoop(obj) { i, _ in body(i) } + } + public func buildForOfLoop( _ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, - _ body: ([Variable]) -> Void + _ body: ([Variable], Variable) -> Void ) { let instr = emit( BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), withInputs: [obj]) - body(Array(instr.innerOutputs)) + let label = instr.innerOutputs.last! + let vars = instr.innerOutputs.dropLast() + body(Array(vars), label) emit(EndForOfLoop()) } - public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> Void) { - let i = emit(BeginRepeatLoop(iterations: numIterations)).innerOutput - body(i) + public func buildForOfLoop( + _ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, + _ body: ([Variable]) -> Void + ) { + buildForOfLoop(obj, selecting: indices, hasRestElement: hasRestElement) { vars, _ in + body(vars) + } + } + + public func buildRepeatLoop(n numIterations: Int, _ body: (Variable, Variable) -> Void) { + let instr = emit(BeginRepeatLoop(iterations: numIterations)) + body(instr.innerOutput(0), instr.innerOutput(1)) emit(EndRepeatLoop()) } + public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> Void) { + buildRepeatLoop(n: numIterations) { i, _ in body(i) } + } + public func buildRepeatLoop(n numIterations: Int, _ body: () -> Void) { emit(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) body() emit(EndRepeatLoop()) } - public func loopBreak() { - emit(LoopBreak()) + public func loopBreak(_ label: Variable? = nil) { + if let label { + emit(LoopBreak(hasLabel: true), withInputs: [label], types: [.jsLoopLabel]) + } else { + emit(LoopBreak()) + } } - public func loopContinue() { - emit(LoopContinue(), withInputs: []) + public func loopContinue(_ label: Variable? = nil) { + if let label { + emit(LoopContinue(hasLabel: true), withInputs: [label], types: [.jsLoopLabel]) + } else { + emit(LoopContinue()) + } } public func buildTryCatchFinally( diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 8bc94f6db..2a20d8092 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2797,11 +2797,13 @@ public let CodeGenerators: [CodeGenerator] = [ ]), CodeGenerator("LoopBreakGenerator", inContext: .single(.loop)) { b in - b.loopBreak() + let label = probability(0.2) ? b.randomVariable(ofType: .jsLoopLabel) : nil + b.loopBreak(label) }, CodeGenerator("ContinueGenerator", inContext: .single(.loop)) { b in - b.loopContinue() + let label = probability(0.2) ? b.randomVariable(ofType: .jsLoopLabel) : nil + b.loopContinue(label) }, CodeGenerator( diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 6d2fa4d1e..b6ce422de 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -529,6 +529,7 @@ public class JavaScriptCompiler { // Process body outputs = emit(BeginForLoopBody(numLoopVariables: loopVariables.count)).innerOutputs + .dropLast() try enterNewScope { zip(loopVariables, outputs).forEach({ map($0, to: $1) }) try compileBody(forLoop.body) @@ -545,7 +546,7 @@ public class JavaScriptCompiler { let obj = try compileExpression(forInLoop.right) - let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput + let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput(0) try enterNewScope { map(initializer.name, to: loopVar) try compileBody(forInLoop.body) @@ -562,7 +563,7 @@ public class JavaScriptCompiler { let obj = try compileExpression(forOfLoop.right) - let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput + let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput(0) try enterNewScope { map(initializer.name, to: loopVar) try compileBody(forOfLoop.body) diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index 1118a7073..4ca42dce2 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -296,7 +296,7 @@ public struct Code: Collection { throw FuzzilliError.codeVerificationError("for-loop header is inconsistent") } } else if instr.op is BeginForLoopBody { - guard instr.numInnerOutputs == forLoopHeaderStack.pop() else { + guard instr.numInnerOutputs == forLoopHeaderStack.pop() + 1 else { throw FuzzilliError.codeVerificationError("for-loop header is inconsistent") } } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ab49ed0ae..3f9109d77 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -2341,7 +2341,7 @@ extension Instruction: ProtobufConvertible { // First input is the condition op = BeginForLoopAfterthought(numLoopVariables: inouts.count - 1) case .beginForLoopBody: - op = BeginForLoopBody(numLoopVariables: inouts.count) + op = BeginForLoopBody(numLoopVariables: inouts.count - 1) case .endForLoop: op = EndForLoop() case .beginForInLoop: @@ -2361,9 +2361,9 @@ extension Instruction: ProtobufConvertible { case .endRepeatLoop: op = EndRepeatLoop() case .loopBreak: - op = LoopBreak() + op = LoopBreak(hasLabel: inouts.count > 0) case .loopContinue: - op = LoopContinue() + op = LoopContinue(hasLabel: inouts.count > 0) case .beginTry: op = BeginTry() case .beginCatch: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index c7992206c..e1b2be313 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -2134,25 +2134,35 @@ public struct JSTyper: Analyzer { zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) }) case .beginForLoopBody: - let inputTypes = activeForLoopVariableTypes.pop() + let inputTypes = activeForLoopVariableTypes.pop() + [.jsLoopLabel] assert(inputTypes.count == instr.numInnerOutputs) zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) }) + case .beginWhileLoopBody: + set(instr.innerOutput, .jsLoopLabel) + + case .beginDoWhileLoopBody: + set(instr.innerOutput, .jsLoopLabel) + case .beginForInLoop: - set(instr.innerOutput, .string) + set(instr.innerOutput(0), .string) + set(instr.innerOutput(1), .jsLoopLabel) case .beginForOfLoop: - set(instr.innerOutput, .jsAnything) + set(instr.innerOutput(0), .jsAnything) + set(instr.innerOutput(1), .jsLoopLabel) case .beginForOfLoopWithDestruct: - for v in instr.innerOutputs { + for v in instr.innerOutputs.dropLast() { set(v, .jsAnything) } + set(instr.innerOutputs.last!, .jsLoopLabel) case .beginRepeatLoop(let op): if op.exposesLoopCounter { - set(instr.innerOutput, .integer) + set(instr.innerOutput(0), .integer) } + set(instr.innerOutputs.last!, .jsLoopLabel) case .beginCatch: set(instr.innerOutput, .jsAnything) diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 14e74f42d..df1e76976 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -2186,12 +2186,14 @@ final class BeginWhileLoopHeader: JsOperation { } // The input is the loop condition. This also prevents empty loop headers which are forbidden by the language. +// The innerOutput is the label of the loop. final class BeginWhileLoopBody: JsOperation { override var opcode: Opcode { .beginWhileLoopBody(self) } init() { super.init( - numInputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + numInputs: 1, numInnerOutputs: 1, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } } @@ -2204,11 +2206,13 @@ final class EndWhileLoop: JsOperation { } } +// The innerOutput is the label of the loop. final class BeginDoWhileLoopBody: JsOperation { override var opcode: Opcode { .beginDoWhileLoopBody(self) } init() { super.init( + numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } @@ -2304,16 +2308,17 @@ final class BeginForLoopAfterthought: JsOperation { } } +// Note: The last innerOutput is the label of the loop. final class BeginForLoopBody: JsOperation { override var opcode: Opcode { .beginForLoopBody(self) } var numLoopVariables: Int { - return numInnerOutputs + return numInnerOutputs - 1 } init(numLoopVariables: Int) { super.init( - numInnerOutputs: numLoopVariables, + numInnerOutputs: numLoopVariables + 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } @@ -2327,12 +2332,13 @@ final class EndForLoop: JsOperation { } } +// Note: The last innerOutput is the label of the loop. final class BeginForInLoop: JsOperation { override var opcode: Opcode { .beginForInLoop(self) } init() { super.init( - numInputs: 1, numInnerOutputs: 1, + numInputs: 1, numInnerOutputs: 2, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } @@ -2346,17 +2352,19 @@ final class EndForInLoop: JsOperation { } } +// Note: The last innerOutput is the label of the loop. final class BeginForOfLoop: JsOperation { override var opcode: Opcode { .beginForOfLoop(self) } init() { super.init( - numInputs: 1, numInnerOutputs: 1, + numInputs: 1, numInnerOutputs: 2, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } } +// Note: The last innerOutput is the label of the loop. final class BeginForOfLoopWithDestruct: JsOperation { override var opcode: Opcode { .beginForOfLoopWithDestruct(self) } @@ -2368,7 +2376,7 @@ final class BeginForOfLoopWithDestruct: JsOperation { self.indices = indices self.hasRestElement = hasRestElement super.init( - numInputs: 1, numInnerOutputs: indices.count, + numInputs: 1, numInnerOutputs: indices.count + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } @@ -2385,6 +2393,7 @@ final class EndForOfLoop: JsOperation { // A loop that simply runs N times and is therefore always guaranteed to terminate. // Useful for example to force JIT compilation without creating more complex loops, which can often quickly end up turning into infinite loops due to mutations. // These could be lifted simply as `for (let i = 0; i < N; i++) { body() }` +// Note: The last innerOutput is the label of the loop. final class BeginRepeatLoop: JsOperation { override var opcode: Opcode { .beginRepeatLoop(self) } @@ -2392,14 +2401,13 @@ final class BeginRepeatLoop: JsOperation { // Whether the current iteration number is exposed as an inner output variable. var exposesLoopCounter: Bool { - assert(numInnerOutputs == 0 || numInnerOutputs == 1) - return numInnerOutputs == 1 + return numInnerOutputs == 2 } init(iterations: Int, exposesLoopCounter: Bool = true) { self.iterations = iterations super.init( - numInnerOutputs: exposesLoopCounter ? 1 : 0, + numInnerOutputs: exposesLoopCounter ? 2 : 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } @@ -2416,16 +2424,20 @@ final class EndRepeatLoop: JsOperation { final class LoopBreak: JsOperation { override var opcode: Opcode { .loopBreak(self) } - init() { - super.init(attributes: [.isJump], requiredContext: [.javascript, .loop]) + init(hasLabel: Bool = false) { + super.init( + numInputs: hasLabel ? 1 : 0, attributes: [.isJump], + requiredContext: [.javascript, .loop]) } } final class LoopContinue: JsOperation { override var opcode: Opcode { .loopContinue(self) } - init() { - super.init(attributes: [.isJump], requiredContext: [.javascript, .loop]) + init(hasLabel: Bool = false) { + super.init( + numInputs: hasLabel ? 1 : 0, attributes: [.isJump], + requiredContext: [.javascript, .loop]) } } diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index a19b294c1..338295c3d 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -238,6 +238,9 @@ public struct ILType: Hashable { /// A label that allows rethrowing the caught exception of a catch block. public static let wasmExceptionLabel: ILType = ILType(definiteType: .wasmExceptionLabel) + /// A label for a statement, e.g. for break and continue. + public static let jsLoopLabel: ILType = ILType(definiteType: .jsLoopLabel) + public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) -> ILType { @@ -1250,6 +1253,8 @@ extension ILType: CustomStringConvertible { return ".wasmLabel(\(labelType.parameters))" } return ".wasmLabel" + case .jsLoopLabel: + return ".jsLoopLabel" case .wasmRef: guard let refType = self.wasmReferenceType else { return ".wasmGenericRef" @@ -1359,6 +1364,9 @@ struct BaseType: OptionSet, Hashable { static let wasmDataSegment = BaseType(rawValue: 1 << 24) static let wasmElementSegment = BaseType(rawValue: 1 << 25) + // A label for a statement, e.g. for break and continue. + static let jsLoopLabel = BaseType(rawValue: 1 << 26) + static let jsAnything = BaseType([ .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable, @@ -1372,7 +1380,7 @@ struct BaseType: OptionSet, Hashable { static let allBaseTypes: [BaseType] = [ .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable, .wasmf32, .wasmi32, .wasmf64, .wasmi64, - .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef, + .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef, .jsLoopLabel, ] } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index dc7d7af68..22c9828a8 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -680,7 +680,7 @@ public class FuzzILLifter: Lifter { case .beginWhileLoopBody: w.decreaseIndentionLevel() - w.emit("BeginWhileLoopBody \(input(0))") + w.emit("BeginWhileLoopBody \(input(0)) -> \(lift(instr.innerOutputs.last!))") w.increaseIndentionLevel() case .endWhileLoop: @@ -688,7 +688,7 @@ public class FuzzILLifter: Lifter { w.emit("EndWhileLoop") case .beginDoWhileLoopBody: - w.emit("BeginDoWhileLoopBody") + w.emit("BeginDoWhileLoopBody -> \(lift(instr.innerOutputs.last!))") w.increaseIndentionLevel() case .beginDoWhileLoopHeader: @@ -726,12 +726,8 @@ public class FuzzILLifter: Lifter { case .beginForLoopBody(let op): w.decreaseIndentionLevel() - if op.numLoopVariables > 0 { - let loopVariables = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginForLoopBody -> \(loopVariables)") - } else { - w.emit("BeginForLoopBody") - } + let loopVariablesAndLabel = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginForLoopBody -> \(loopVariablesAndLabel)") w.increaseIndentionLevel() case .endForLoop: @@ -739,7 +735,8 @@ public class FuzzILLifter: Lifter { w.emit("EndForLoop") case .beginForInLoop: - w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") + let outputs = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginForInLoop \(input(0)) -> \(outputs)") w.increaseIndentionLevel() case .endForInLoop: @@ -747,13 +744,15 @@ public class FuzzILLifter: Lifter { w.emit("EndForInLoop") case .beginForOfLoop: - w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())") + let outputs = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginForOfLoop \(input(0)) -> \(outputs)") w.increaseIndentionLevel() case .beginForOfLoopWithDestruct(let op): - let outputs = instr.innerOutputs.map(lift) + let outputs = instr.innerOutputs.dropLast().map(lift) + let label = lift(instr.innerOutputs.last!) w.emit( - "BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))]" + "BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))], \(label)" ) w.increaseIndentionLevel() @@ -762,11 +761,9 @@ public class FuzzILLifter: Lifter { w.emit("EndForOfLoop") case .beginRepeatLoop(let op): - if op.exposesLoopCounter { - w.emit("BeginRepeatLoop '\(op.iterations)' -> \(innerOutput())") - } else { - w.emit("BeginRepeatLoop '\(op.iterations)'") - } + let outputs = instr.innerOutputs.map(lift).joined(separator: ", ") + assert(!outputs.isEmpty) + w.emit("BeginRepeatLoop '\(op.iterations)' -> \(outputs)") w.increaseIndentionLevel() case .endRepeatLoop: @@ -775,10 +772,18 @@ public class FuzzILLifter: Lifter { case .loopBreak, .switchBreak: - w.emit("Break") + if instr.hasInputs { + w.emit("Break \(input(0))") + } else { + w.emit("Break") + } case .loopContinue: - w.emit("Continue") + if instr.hasInputs { + w.emit("Continue \(input(0))") + } else { + w.emit("Continue") + } case .beginTry: w.emit("BeginTry") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 858c62af5..9695d10f2 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1293,7 +1293,8 @@ public class JavaScriptLifter: Lifter { case .beginWhileLoopBody: let COND = handleEndSingleExpressionContext(result: input(0), with: &w) - w.emitBlock("while (\(COND)) {") + let prefix = w.labelPrefix(for: instr.innerOutput) + w.emitBlock("\(prefix)while (\(COND)) {") w.enterNewBlock() case .endWhileLoop: @@ -1301,7 +1302,8 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .beginDoWhileLoopBody: - w.emit("do {") + let prefix = w.labelPrefix(for: instr.innerOutput) + w.emitBlock("\(prefix)do {") w.enterNewBlock() case .beginDoWhileLoopHeader: @@ -1390,22 +1392,25 @@ public class JavaScriptLifter: Lifter { var CONDITION = header.condition var AFTERTHOUGHT = handleEndSingleExpressionContext(with: &w) + let labelVar = instr.innerOutput(instr.numInnerOutputs - 1) + let prefix = w.labelPrefix(for: labelVar) + if !INITIALIZER.contains("\n") && !CONDITION.contains("\n") && !AFTERTHOUGHT.contains("\n") { if !CONDITION.isEmpty { CONDITION = " " + CONDITION } if !AFTERTHOUGHT.isEmpty { AFTERTHOUGHT = " " + AFTERTHOUGHT } - w.emit("for (\(INITIALIZER);\(CONDITION);\(AFTERTHOUGHT)) {") + w.emit("\(prefix)for (\(INITIALIZER);\(CONDITION);\(AFTERTHOUGHT)) {") } else { w.emitBlock( """ - for (\(INITIALIZER); + \(prefix)for (\(INITIALIZER); \(CONDITION); \(AFTERTHOUGHT)) { """) } - w.declareAll(instr.innerOutputs, as: header.loopVariables) + w.declareAll(instr.innerOutputs.dropLast(), as: header.loopVariables) w.enterNewBlock() case .endForLoop: @@ -1413,10 +1418,14 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .beginForInLoop: - let LET = w.declarationKeyword(for: instr.innerOutput) - let V = w.declare(instr.innerOutput) + let LET = w.declarationKeyword(for: instr.innerOutput(0)) + let V = w.declare(instr.innerOutput(0)) let OBJ = input(0) - w.emit("for (\(LET) \(V) in \(OBJ)) {") + + let labelVar = instr.innerOutputs.last! + let prefix = w.labelPrefix(for: labelVar) + + w.emit("\(prefix)for (\(LET) \(V) in \(OBJ)) {") w.enterNewBlock() case .endForInLoop: @@ -1424,19 +1433,27 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .beginForOfLoop: - let V = w.declare(instr.innerOutput) - let LET = w.declarationKeyword(for: instr.innerOutput) + let V = w.declare(instr.innerOutput(0)) + let LET = w.declarationKeyword(for: instr.innerOutput(0)) let OBJ = input(0) - w.emit("for (\(LET) \(V) of \(OBJ)) {") + + let labelVar = instr.innerOutputs.last! + let prefix = w.labelPrefix(for: labelVar) + + w.emit("\(prefix)for (\(LET) \(V) of \(OBJ)) {") w.enterNewBlock() case .beginForOfLoopWithDestruct(let op): - let outputs = w.declareAll(instr.innerOutputs) + let outputs = w.declareAll(instr.innerOutputs.dropLast()) let PATTERN = liftArrayDestructPattern( indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement) let LET = w.varKeyword let OBJ = input(0) - w.emit("for (\(LET) [\(PATTERN)] of \(OBJ)) {") + + let labelVar = instr.innerOutputs.last! + let prefix = w.labelPrefix(for: labelVar) + + w.emit("\(prefix)for (\(LET) [\(PATTERN)] of \(OBJ)) {") w.enterNewBlock() case .endForOfLoop: @@ -1447,24 +1464,38 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let I: String if op.exposesLoopCounter { - I = w.declare(instr.innerOutput) + I = w.declare(instr.innerOutput(0)) } else { I = "i" } + + let labelVar = instr.innerOutputs.last! + let prefix = w.labelPrefix(for: labelVar) + let ITERATIONS = op.iterations - w.emit("for (\(LET) \(I) = 0; \(I) < \(ITERATIONS); \(I)++) {") + w.emit("\(prefix)for (\(LET) \(I) = 0; \(I) < \(ITERATIONS); \(I)++) {") w.enterNewBlock() case .endRepeatLoop: w.leaveCurrentBlock() w.emit("}") - case .loopBreak(_), - .switchBreak: + case .loopBreak(_): + if instr.hasInputs { + w.emit("break \(input(0));") + } else { + w.emit("break;") + } + + case .switchBreak: w.emit("break;") case .loopContinue: - w.emit("continue;") + if instr.hasInputs { + w.emit("continue \(input(0));") + } else { + w.emit("continue;") + } case .beginTry: w.emit("try {") @@ -2466,6 +2497,15 @@ public class JavaScriptLifter: Lifter { } } + /// Returns a label prefix (e.g. "L1: ") if the label variable is used, otherwise an empty string. + mutating func labelPrefix(for labelVar: Variable) -> String { + if analyzer.numUses(of: labelVar) > 0 { + let label = declare(labelVar, as: "L" + String(labelVar.number)) + return "\(label): " + } + return "" + } + mutating func enterNewBlock() { emitPendingExpressions() writer.increaseIndentionLevel() diff --git a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index 6acce260b..d3e728d64 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -95,13 +95,19 @@ struct LoopSimplifier: Reducer { let conditionBlock = group.block(1) let beginConditionBlock = helper.code[conditionBlock.head] assert(beginConditionBlock.op is BeginForLoopCondition) + + let bodyBlock = group.block(3) + let beginBodyBlock = helper.code[bodyBlock.head] + assert(beginBodyBlock.op is BeginForLoopBody) + let headerIndex = newCode.count let needLoopVariable = beginConditionBlock.numInnerOutputs > 0 let loopVar = needLoopVariable ? beginConditionBlock.innerOutput(0) : nil + let labelVar = beginBodyBlock.innerOutput(beginBodyBlock.numInnerOutputs - 1) newCode.append( Instruction( BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), - inouts: needLoopVariable ? [loopVar!] : [])) + inouts: needLoopVariable ? [loopVar!, labelVar] : [labelVar])) // Append condition, body, and afterthought code var replacements = [Variable: Variable]( @@ -111,10 +117,11 @@ struct LoopSimplifier: Reducer { newCode.append(Instruction(instr.op, inouts: newInouts)) } - let bodyBlock = group.block(3) assert(helper.code[bodyBlock.head].op is BeginForLoopBody) replacements = [Variable: Variable]( - uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) + uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.dropLast().map({ + ($0, loopVar!) + })) for instr in helper.code.body(of: bodyBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts)) @@ -160,7 +167,14 @@ struct LoopSimplifier: Reducer { var newCode = [Instruction]() // Append loop header - newCode.append(Instruction(BeginRepeatLoop(iterations: 1, exposesLoopCounter: false))) + let bodyBlock = group.block(1) + let beginWhileLoopBody = helper.code[bodyBlock.head] + assert(beginWhileLoopBody.op is BeginWhileLoopBody) + let label = beginWhileLoopBody.innerOutput + + let repeatOp = BeginRepeatLoop(iterations: 1, exposesLoopCounter: false) + let repeatInouts = [label] + newCode.append(Instruction(repeatOp, inouts: repeatInouts)) // Append loop header and body code let headerBlock = group.block(0) @@ -169,7 +183,6 @@ struct LoopSimplifier: Reducer { newCode.append(instr) } - let bodyBlock = group.block(1) assert(helper.code[bodyBlock.head].op is BeginWhileLoopBody) for instr in helper.code.body(of: bodyBlock) { newCode.append(instr) @@ -204,10 +217,16 @@ struct LoopSimplifier: Reducer { var newCode = [Instruction]() // Append loop header - newCode.append(Instruction(BeginRepeatLoop(iterations: 1, exposesLoopCounter: false))) + let bodyBlock = group.block(0) + let beginDoWhileLoopBody = helper.code[bodyBlock.head] + assert(beginDoWhileLoopBody.op is BeginDoWhileLoopBody) + let label = beginDoWhileLoopBody.innerOutput + + let repeatOp = BeginRepeatLoop(iterations: 1, exposesLoopCounter: false) + let repeatInouts = [label] + newCode.append(Instruction(repeatOp, inouts: repeatInouts)) // Append loop body and header code - let bodyBlock = group.block(0) assert(helper.code[bodyBlock.head].op is BeginDoWhileLoopBody) for instr in helper.code.body(of: bodyBlock) { newCode.append(instr) @@ -240,15 +259,11 @@ struct LoopSimplifier: Reducer { // We should never increase the number of iterations return } - let replacement: Instruction - if originalLoopHeader.exposesLoopCounter { - replacement = Instruction( - BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: helper.code[group.head].inouts) - } else { - replacement = Instruction( - BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) - } + let repeatOp = BeginRepeatLoop( + iterations: numIterations, exposesLoopCounter: originalLoopHeader.exposesLoopCounter + ) + let replacement = Instruction( + repeatOp, inouts: helper.code[group.head].inouts) if helper.tryReplacing( instructionAt: group.head, with: replacement, numExecutions: numTestExecutions) { @@ -262,16 +277,12 @@ struct LoopSimplifier: Reducer { loopHeaderIndexInNewCode headerIndex: Int, using helper: MinimizationHelper ) { var newCode = newCode - assert(newCode[headerIndex].op is BeginRepeatLoop) + let originalOp = newCode[headerIndex].op as! BeginRepeatLoop for numIterations in commonLoopIterationCounts { - if newCode[headerIndex].numInnerOutputs > 0 { - newCode[headerIndex] = Instruction( - BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: newCode[headerIndex].inouts) - } else { - newCode[headerIndex] = Instruction( - BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) - } + let repeatOp = BeginRepeatLoop( + iterations: numIterations, exposesLoopCounter: originalOp.exposesLoopCounter) + newCode[headerIndex] = Instruction( + repeatOp, inouts: newCode[headerIndex].inouts) // After this change, the variable numbers may no longer be sequential as we may have removed instructions with inner outputs. So we need to also renumber the variables. if helper.tryReplacing( range: range, with: newCode, renumberVariables: true, @@ -350,23 +361,30 @@ struct LoopSimplifier: Reducer { var replacements = [(Int, Instruction)]() replacements.append((innerHead, Instruction(Nop()))) replacements.append((innerTail, Instruction(Nop()))) + + let outerLabel = helper.code[outerHead].innerOutputs.last! + let innerLabel = helper.code[innerHead].innerOutputs.last! + if !outer.exposesLoopCounter && !inner.exposesLoopCounter { // The simplest case: only need to replace the loop instructions and not deal with loop counters at all assert(!newHead.exposesLoopCounter) - replacements.append((outerHead, Instruction(newHead))) + let inouts = [outerLabel] + replacements.append((outerHead, Instruction(newHead, inouts: inouts))) } else if !outer.exposesLoopCounter || !inner.exposesLoopCounter { // Another simple case: only need to replace the loop instructions and reuse the one existing loop counter variable assert(newHead.exposesLoopCounter) let loopVar = outer.exposesLoopCounter - ? helper.code[outerHead].innerOutput : helper.code[innerHead].innerOutput - replacements.append((outerHead, Instruction(newHead, innerOutput: loopVar))) + ? helper.code[outerHead].innerOutput(0) : helper.code[innerHead].innerOutput(0) + let inouts = [loopVar, outerLabel] + replacements.append((outerHead, Instruction(newHead, inouts: inouts))) } else { // The more complicated case: we also need to rebind references to the inner loop's counter variable to the new counter variable - let loopVar = helper.code[outerHead].innerOutput - replacements.append((outerHead, Instruction(newHead, innerOutput: loopVar))) + let loopVar = helper.code[outerHead].innerOutput(0) + let inouts = [loopVar, outerLabel] + replacements.append((outerHead, Instruction(newHead, inouts: inouts))) - let innerLoopVar = helper.code[innerHead].innerOutput + let innerLoopVar = helper.code[innerHead].innerOutput(0) for instr in helper.code[innerHead..