diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 19f5536db..bc70a382b 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -25,21 +25,24 @@ 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 - name: Build - run: swift build -c ${{ matrix.kind }} -v + run: swift build -c ${{ matrix.kind }} - name: Install protobuf # Install protoc so the presubmit can also validate the generated *.pb.swift files. if: ${{ matrix.os == 'ubuntu-latest' && matrix.kind == 'debug' }} - run: sudo apt install -y protobuf-compiler + run: sudo apt update && sudo apt install -y protobuf-compiler + - name: Install Node.js dependencies for Compiler/Parser tests + working-directory: ./Sources/Fuzzilli/Compiler/Parser + run: npm install - name: Run presubmit checks if: ${{ matrix.os == 'ubuntu-latest' && matrix.kind == 'debug' }} run: python3 Tools/presubmit.py - name: Run tests with Node.js - run: swift test -c ${{ matrix.kind }} -v + run: swift test -c ${{ matrix.kind }} - name: Install jsvu run: npm install jsvu -g - name: Install d8 diff --git a/.swift-format b/.swift-format new file mode 100644 index 000000000..36423a346 --- /dev/null +++ b/.swift-format @@ -0,0 +1,79 @@ +{ + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "indentBlankLines" : false, + "indentConditionalCompilationBlocks" : true, + "indentSwitchCaseLabels" : false, + "indentation" : { + "spaces" : 4 + }, + "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 +} diff --git a/Package.swift b/Package.swift index 216cf67c3..e19a9dbee 100644 --- a/Package.swift +++ b/Package.swift @@ -19,60 +19,86 @@ import PackageDescription let package = Package( name: "Fuzzilli", platforms: [ - .macOS(.v13), + .macOS(.v13) ], products: [ - .library(name: "Fuzzilli",targets: ["Fuzzilli"]), + .library(name: "Fuzzilli", targets: ["Fuzzilli"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.31.0"), + // We use an exact version here as we also use this version to generate the .pb.swift to + // ensure that they are always regenerated with a consistent version. So this entry locks + // the version. It can be bumped arbitrarily, however, the generated files should be + // 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"]), - .testTarget(name: "FuzzilliTests", - dependencies: ["Fuzzilli"], - resources: [.copy("CompilerTests")]), + // 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: "FuzzilliDetectMissingBuiltins", dependencies: ["Fuzzilli"]), + + .testTarget( + name: "FuzzilliTests", + dependencies: ["Fuzzilli"], + resources: [.copy("CompilerTests")]), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/Dumpling/dumpling_fuzzilli.patch b/Sources/Dumpling/dumpling_fuzzilli.patch deleted file mode 100644 index deb0b6770..000000000 --- a/Sources/Dumpling/dumpling_fuzzilli.patch +++ /dev/null @@ -1,13010 +0,0 @@ -diff --git a/Package.swift b/Package.swift -index 05e5dc1..540b552 100644 ---- a/Package.swift -+++ b/Package.swift -@@ -56,18 +56,22 @@ let package = Package( - .copy("Protobuf/ast.proto"), - .copy("Compiler/Parser")]), - -+ .target(name: "FuzzILTool", -+ dependencies: ["Fuzzilli"]), -+ - .target(name: "REPRLRun", - dependencies: ["libreprl"]), - - .target(name: "FuzzilliCli", - dependencies: ["Fuzzilli"]), -- -- .target(name: "FuzzILTool", -+ -+ .target(name: "RelateTool", - dependencies: ["Fuzzilli"]), - -+ - .testTarget(name: "FuzzilliTests", - dependencies: ["Fuzzilli"], -- resources: [.copy("CompilerTests")]), -+ resources: [ .copy("CompilerTests"), ]), - ], - swiftLanguageVersions: [.v5] - ) -diff --git a/Sources/Fuzzilli/Base/Contributor.swift b/Sources/Fuzzilli/Base/Contributor.swift -index fd0af2a..6497f83 100644 ---- a/Sources/Fuzzilli/Base/Contributor.swift -+++ b/Sources/Fuzzilli/Base/Contributor.swift -@@ -29,6 +29,14 @@ public class Contributor: Hashable { - // Number of crashing programs produced. - private var crashingSamples = 0 - -+ private var differentialSamples = 0 -+ -+ private var turbofanSamples = 0 -+ -+ private var maglevSamples = 0 -+ -+ private var sparkplugSamples = 0 -+ - // Number of times this instance failed to generate/mutate code. - private var failures = 0 - // Total number of instructions added to programs by this contributor. -@@ -58,6 +66,21 @@ public class Contributor: Hashable { - crashingSamples += 1 - } - -+ func generatedDifferentialSample() { -+ differentialSamples += 1 -+ } -+ -+ func generatedTurbofanSample() { -+ turbofanSamples += 1 -+ } -+ -+ func generatedMaglevSample() { -+ maglevSamples += 1 -+ } -+ -+ func generatedSparkplugSample() { -+ sparkplugSamples += 1 -+ } - - func addedInstructions(_ n: Int) { - guard n > 0 else { return } -@@ -72,6 +95,22 @@ public class Contributor: Hashable { - return crashingSamples - } - -+ public var differentialsFound: Int { -+ return differentialSamples -+ } -+ -+ public var turbofanSamplesFound: Int { -+ return turbofanSamples -+ } -+ -+ public var maglevSamplesFound: Int { -+ return maglevSamples -+ } -+ -+ public var sparkplugSamplesFound: Int { -+ return sparkplugSamples -+ } -+ - public var totalSamples: Int { - return validSamples + interestingSamples + invalidSamples + timedOutSamples + crashingSamples - } -@@ -135,4 +174,20 @@ extension Contributors { - public func generatedTimeOutSample() { - forEach { $0.generatedTimeOutSample() } - } -+ -+ public func generatedDifferentialSample() { -+ forEach { $0.generatedDifferentialSample() } -+ } -+ -+ public func generatedTurbofanSample() { -+ forEach { $0.generatedTurbofanSample() } -+ } -+ -+ public func generatedMaglevSample() { -+ forEach { $0.generatedMaglevSample() } -+ } -+ -+ public func generatedSparkplugSample() { -+ forEach { $0.generatedSparkplugSample() } -+ } - } -diff --git a/Sources/Fuzzilli/Base/Events.swift b/Sources/Fuzzilli/Base/Events.swift -index 7063add..4d5d2ad 100644 ---- a/Sources/Fuzzilli/Base/Events.swift -+++ b/Sources/Fuzzilli/Base/Events.swift -@@ -55,6 +55,12 @@ public class Events { - /// 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 DifferentialFound = Event<(program: Program, behaviour: CrashBehaviour, origin: ProgramOrigin, opt_stdout: String?, unopt_stdout: String, reproducesInNonReplMode: Bool)>() -+ -+ public let JITExecutingProgramFound = Event<(program: Program, compilers: [JITType], is_optimizing: Bool)>() -+ -+ public let RelationPerformed = Event<(program: Program, execution: Execution)>() -+ - /// Signals that a program causing a timeout has been found. - public let TimeOutFound = Event() - -@@ -88,6 +94,12 @@ public class Events { - public let CorpusImportComplete = Event<()>() - } - -+public enum JITType: String { -+ case sparkplug = "sparkplug" -+ case maglev = "maglev" -+ case turbofan = "turbofan" -+} -+ - /// Crash behavior of a program. - public enum CrashBehaviour: String { - case deterministic = "deterministic" -diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift -index 6429536..b57e3d5 100644 ---- a/Sources/Fuzzilli/Configuration.swift -+++ b/Sources/Fuzzilli/Configuration.swift -@@ -12,6 +12,37 @@ - // See the License for the specific language governing permissions and - // limitations under the License. - -+public struct V8DifferentialConfig { -+ public let commonArgs: [String] = [ -+ "--expose-gc", -+ "--omit-quit", -+ "--allow-natives-for-differential-fuzzing", -+ "--fuzzing", -+ "--future", -+ "--harmony", -+ "--predictable", -+ "--trace", -+ "--correctness-fuzzer-suppressions", -+ "--no-lazy-feedback-allocation", -+ ] -+ -+ public let differentialArgs: [String] = [ -+ "--turbofan-dumping", -+ "--generate-dump-positions", -+ // "--verify-heap-on-jit-dump", -+ "--turbofan-dumping-print-deopt-frames", -+ "--jit-return-dump", -+ "--maglev-dumping", -+ "--no-sparkplug", -+ "--jit-fuzzing", -+ ] -+ -+ public let referenceArgs: [String] = ["--no-turbofan", "--no-maglev", "--load-dump-positions", "--sparkplug-dumping", "--interpreter-dumping"] -+ -+ public init() {} -+} -+ -+ - public struct Configuration { - /// The commandline arguments used by this instance. - public let arguments: [String] -@@ -26,6 +57,15 @@ public struct Configuration { - /// Used to verify that crashes can be detected. - public let crashTests: [String] - -+ /// Code snippets that cause an observable difference of output -+ /// in the target engine. Used to verify that crashes can be detected. -+ public let differentialTests: [String] -+ -+ /// Code snippets that must not cause an observable difference of output -+ /// in the target engine. Used to verify that common sources of -+ /// entropy (Math.random, ...) are deterministic. -+ public let differentialTestsInvariant: [String] -+ - /// The fraction of instruction to keep from the original program when minimizing. - /// This setting is useful to avoid "over-minimization", which can negatively impact the fuzzer's - /// performance if program features are removed that could later be mutated to trigger new -@@ -57,28 +97,48 @@ public struct Configuration { - /// also appended as a comment in the footer of crashing samples. - public let tag: String? - -+ public let relateToolPath: String? -+ -+ public let dumplingDepth: UInt32? -+ -+ public let dumplingPropCount: UInt32? -+ -+ public let storagePath: String? -+ - public init(arguments: [String] = [], - timeout: UInt32 = 250, - skipStartupTests: Bool = false, - logLevel: LogLevel = .info, - crashTests: [String] = [], -+ differentialTests: [String] = [], -+ differentialTestsInvariant: [String] = [], - minimizationLimit: Double = 0.0, - dropoutRate: Double = 0, - collectRuntimeTypes: Bool = false, - enableDiagnostics: Bool = false, - enableInspection: Bool = false, - staticCorpus: Bool = false, -- tag: String? = nil) { -+ tag: String? = nil, -+ relateToolPath: String? = nil, -+ dumplingDepth: UInt32 = 3, -+ dumplingPropCount: UInt32 = 5, -+ storagePath: String? = nil) { - self.arguments = arguments - self.timeout = timeout - self.logLevel = logLevel - self.crashTests = crashTests -+ self.differentialTests = differentialTests -+ self.differentialTestsInvariant = differentialTestsInvariant - self.dropoutRate = dropoutRate - self.minimizationLimit = minimizationLimit - self.enableDiagnostics = enableDiagnostics - self.enableInspection = enableInspection - self.staticCorpus = staticCorpus - self.tag = tag -+ self.relateToolPath = relateToolPath -+ self.dumplingDepth = dumplingDepth -+ self.dumplingPropCount = dumplingPropCount -+ self.storagePath = storagePath - } - } - -diff --git a/Sources/Fuzzilli/DifferentialOracle/Oracle.swift b/Sources/Fuzzilli/DifferentialOracle/Oracle.swift -new file mode 100644 -index 0000000..1d91f18 ---- /dev/null -+++ b/Sources/Fuzzilli/DifferentialOracle/Oracle.swift -@@ -0,0 +1,211 @@ -+import Foundation -+ -+public enum FrameType { -+ case interpreter -+ case sparkplug -+ case maglev -+ case turbofan -+ case deopt -+ case jitReturn -+} -+ -+ -+public struct Frame: Equatable { -+ let bytecode_offset: Int -+ let acc: String -+ let args: [String] -+ let regs: [String] -+ let function_id: Int -+ let frame_type: FrameType -+} -+ -+public enum OracleLogLevel { -+ case none -+ case info -+ case debug -+} -+ -+/// Compare two frames for equality -+/// Warning: It is not communtative! The opt frame must be lhs. -+/// A string value of "" in lhs is equal to every other string -+/// value in acc, args, and regs -+/// - Parameters: -+/// - lhs: The unopt frame -+/// - rhs: The opt frame -+public func == (lhs: Frame, rhs: Frame) -> Bool { -+ return lhs.bytecode_offset == rhs.bytecode_offset && -+ (lhs.acc == rhs.acc || lhs.acc == "") && -+ lhs.args.count == rhs.args.count && -+ lhs.regs.count == rhs.regs.count && -+ (0.." } && -+ (0.." } && -+ lhs.function_id == rhs.function_id -+} -+ -+ -+ -+ -+public func parseDiffFrame(_ frameArr: ArraySlice, _ lastFrame: inout Frame?, -+ _ prevRegs: inout [String], _ prevArgs: inout [String]) -> Frame { -+ 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 -+ return value -+ } -+ return defaultValue -+ } -+ -+ let frameType: FrameType -+ var i = frameArr.startIndex -+ switch frameArr[i] { -+ case "---I": -+ frameType = .interpreter -+ case "---S": -+ frameType = .sparkplug -+ case "---M": -+ frameType = .maglev -+ case "---T": -+ frameType = .turbofan -+ case "---D": -+ frameType = .deopt -+ case "---R": -+ frameType = .jitReturn -+ default: -+ fatalError("Unknown frame type") -+ } -+ i += 1 -+ -+ let bytecode_offset = parseValue(prefix: "b:", defaultValue: lastFrame?.bytecode_offset ?? 4242, index: &i){ Int($0)! } -+ let function_id = parseValue(prefix: "f:", defaultValue: lastFrame?.function_id ?? 4242, index: &i){ Int($0)! } -+ let arg_count = parseValue(prefix: "n:", defaultValue: lastFrame?.args.count ?? 4242, index: &i){ Int($0)! } -+ let reg_count = parseValue(prefix: "m:", defaultValue: lastFrame?.regs.count ?? 4242, index: &i){ Int($0)! } -+ let acc = parseValue(prefix: "x:", defaultValue: lastFrame?.acc ?? "", index: &i){ String($0) } -+ -+ func updateValues(prefix: String, totalCount: Int, oldValues: [String], prevValues: inout [String]) -> [String] { -+ var newValues: [String] -+ // performance improvement to use Swifts copy on write -+ if oldValues.count == totalCount { -+ newValues = oldValues -+ } -+ else { -+ newValues = [String]() -+ newValues.reserveCapacity(totalCount) -+ // copy up to totalCount from prevValues into newValues -+ for j in 0.. [[Frame]] { -+ var stack: [[Frame]] = [[], []] -+ var linearized: [[Frame]] = [] -+ var lastFrame: Frame? = nil -+ -+ var prevArgs: [String] = [String]() -+ var prevRegs: [String] = [String]() -+ prevArgs.reserveCapacity(64) -+ prevRegs.reserveCapacity(128) -+ -+ let split = stdout.split(separator: "\n", omittingEmptySubsequences: false) -+ var i = 0 -+ -+ while i < split.count { -+ if split[i] == ">" { -+ stack.append([]) -+ } -+ else if split[i] == "<" { -+ linearized.append(stack.removeLast()) -+ } -+ else if split[i].starts(with: "---") { -+ let start = i -+ while (split[i] != "") { -+ i += 1 -+ } -+ let end = i-1 -+ let frame = split[start...end] -+ // append to last stack frame -+ lastFrame = parseDiffFrame(frame, &lastFrame, &prevArgs, &prevRegs) -+ stack[stack.count - 1].append(lastFrame!) -+ } -+ i += 1 -+ } -+ for _ in stack { -+ linearized.append(stack.removeLast()) -+ } -+ return linearized -+} -+ -+public func relate(_ optIn: String, with unoptIn: String, _ logLevel: OracleLogLevel = .none) -> Bool { -+ // Quick and dirty way to not get NaN vs spam -+ let optChunks = parseToLinear(optIn.replacingOccurrences(of: "", with: "NaN")) -+ let unoptChunks = parseToLinear(unoptIn.replacingOccurrences(of: "", with: "NaN")) -+ -+ -+ if logLevel == .debug { -+ print("opt Chunks:") -+ print(optChunks as AnyObject) -+ print("unopt Chunks:") -+ print(unoptChunks as AnyObject) -+ } -+ if optChunks.count != unoptChunks.count { -+ if logLevel != .none { -+ print("Difference in chunk count \(optChunks.count) != \(unoptChunks.count)") -+ } -+ return false -+ } -+ for (optChunk, unoptChunk) in zip(optChunks, unoptChunks) { -+ for optFrame in optChunk { -+ // check if optFrame is in unoptChunk -+ if !unoptChunk.contains(where: {optFrame == $0}) { -+ if logLevel != .none { -+ print(optFrame as AnyObject) -+ print("--------------------------") -+ print("[") -+ for unoptFrame in unoptChunk { -+ if unoptFrame.bytecode_offset == optFrame.bytecode_offset { -+ print(unoptFrame as AnyObject) -+ } -+ } -+ print("]") -+ } -+ return false -+ } -+ } -+ } -+ return true -+} -diff --git a/Sources/Fuzzilli/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift -index 1b5a610..3a5e76d 100644 ---- a/Sources/Fuzzilli/Engines/FuzzEngine.swift -+++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift -@@ -32,17 +32,27 @@ public class FuzzEngine: ComponentBase { - fatalError("Must be implemented by child classes") - } - -- final func execute(_ program: Program, withTimeout timeout: UInt32? = nil) -> ExecutionOutcome { -+} -+ -+extension FuzzEngine { -+ public func execute(_ program: Program, withTimeout timeout: UInt32? = nil) -> ExecutionOutcome { - let program = postProcessor?.process(program, for: fuzzer) ?? program - - fuzzer.dispatchEvent(fuzzer.events.ProgramGenerated, data: program) - -- let execution = fuzzer.execute(program, withTimeout: timeout, purpose: .fuzzing) -+ let postprocessedProgram: Program -+ postprocessedProgram = program -+ -+ let execution = fuzzer.execute(postprocessedProgram, withTimeout: timeout, purpose: .fuzzing, differentialExecute: .force) - - 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() -+ fuzzer.processCrash(postprocessedProgram, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local, withExectime: execution.execTime) -+ postprocessedProgram.contributors.generatedCrashingSample() -+ -+ case .differential: -+ fuzzer.processDifferential(postprocessedProgram, withStderr: execution.stderr, withStdout: execution.unOptStdout!, origin: .local, optStdout: execution.optStdout!) -+ postprocessedProgram.contributors.generatedDifferentialSample() - - case .succeeded: - fuzzer.dispatchEvent(fuzzer.events.ValidProgramFound, data: program) -@@ -63,19 +73,19 @@ public class FuzzEngine: ComponentBase { - - case .failed(_): - if fuzzer.config.enableDiagnostics { -- program.comments.add("Stdout:\n" + execution.stdout, at: .footer) -+ postprocessedProgram.comments.add("Stdout:\n" + execution.stdout, at: .footer) - } -- fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: program) -- program.contributors.generatedInvalidSample() -+ fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: postprocessedProgram) -+ postprocessedProgram.contributors.generatedInvalidSample() - - case .timedOut: -- fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: program) -- program.contributors.generatedTimeOutSample() -+ fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: postprocessedProgram) -+ postprocessedProgram.contributors.generatedTimeOutSample() - } - - if fuzzer.config.enableDiagnostics { - // Ensure deterministic execution behaviour. This can for example help detect and debug REPRL issues. -- ensureDeterministicExecutionOutcomeForDiagnostic(of: program) -+ ensureDeterministicExecutionOutcomeForDiagnostic(of: postprocessedProgram) - } - - return execution.outcome -diff --git a/Sources/Fuzzilli/Engines/HybridEngine.swift b/Sources/Fuzzilli/Engines/HybridEngine.swift -index f25ab27..4bd0885 100644 ---- a/Sources/Fuzzilli/Engines/HybridEngine.swift -+++ b/Sources/Fuzzilli/Engines/HybridEngine.swift -@@ -24,6 +24,7 @@ public class HybridEngine: FuzzEngine { - case generatedCodeFailed = "Generated code failed" - case generatedCodeTimedOut = "Generated code timed out" - case generatedCodeCrashed = "Generated code crashed" -+ case generatedCodeDifferential = "Generated code differential" - } - private var outcomeCounts = [CodeGenerationOutcome: Int]() - -@@ -112,6 +113,8 @@ public class HybridEngine: FuzzEngine { - return recordOutcome(.generatedCodeTimedOut) - case .crashed: - return recordOutcome(.generatedCodeCrashed) -+ case .differential: -+ return recordOutcome(.generatedCodeDifferential) - } - - // Now perform one round of fixup to improve the generated program based on runtime information and in particular remove all try-catch guards that are not needed. -diff --git a/Sources/Fuzzilli/Evaluation/ProgramAspects.swift b/Sources/Fuzzilli/Evaluation/ProgramAspects.swift -index 7098e72..7cdb6bd 100644 ---- a/Sources/Fuzzilli/Evaluation/ProgramAspects.swift -+++ b/Sources/Fuzzilli/Evaluation/ProgramAspects.swift -@@ -12,12 +12,21 @@ - // See the License for the specific language governing permissions and - // limitations under the License. - -+public enum ExecutionType { -+ case unknown -+ case interpreter -+ case maglev -+ case turbofan -+} -+ - /// Aspects of a program that make it special. - public class ProgramAspects: CustomStringConvertible { - let outcome: ExecutionOutcome -+ public var jitExecution: ExecutionType - -- public init(outcome: ExecutionOutcome) { -+ public init(outcome: ExecutionOutcome, jitExecution: ExecutionType = .unknown) { - self.outcome = outcome -+ self.jitExecution = jitExecution - } - - public var description: String { -diff --git a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift -index c365ff1..0ed5e61 100644 ---- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift -+++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift -@@ -19,11 +19,12 @@ import libcoverage - public class CovEdgeSet: ProgramAspects { - private var numEdges: UInt32 - fileprivate var edges: UnsafeMutablePointer? -+ - -- init(edges: UnsafeMutablePointer?, numEdges: UInt32) { -+ init(edges: UnsafeMutablePointer?, numEdges: UInt32, jitExecution: ExecutionType = .unknown) { - self.numEdges = numEdges - self.edges = edges -- super.init(outcome: .succeeded) -+ super.init(outcome: .succeeded, jitExecution: jitExecution) - } - - deinit { -@@ -192,8 +193,8 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { - return false - } - -- if execution.outcome.isCrash() { -- // For crashes, we don't care about the edges that were triggered, just about the outcome itself. -+ if execution.outcome.isCrash() || execution.outcome == .differential { -+ // For crashes and differentials?, we don't care about the edges that were triggered, just about the outcome itself. - return true - } - -@@ -237,6 +238,15 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { - let intersectedCovEdgeSet = secondCovEdgeSet - intersectedCovEdgeSet.setEdges(intersectedEdgeSet) - -+ if execution.compilersUsed.count != 0 { -+ if execution.compilersUsed.contains(.turbofan) { -+ intersectedCovEdgeSet.jitExecution = .turbofan -+ } -+ else if execution.compilersUsed.contains(.maglev) { -+ intersectedCovEdgeSet.jitExecution = .maglev -+ } -+ // dont care about sparkplug here -+ } - return intersectedCovEdgeSet - } - -diff --git a/Sources/Fuzzilli/Execution/Execution.swift b/Sources/Fuzzilli/Execution/Execution.swift -index 746b446..b6e6e76 100644 ---- a/Sources/Fuzzilli/Execution/Execution.swift -+++ b/Sources/Fuzzilli/Execution/Execution.swift -@@ -20,6 +20,7 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { - case failed(Int) - case succeeded - case timedOut -+ case differential - - public var description: String { - switch self { -@@ -31,6 +32,8 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { - return "Succeeded" - case .timedOut: - return "TimedOut" -+ case .differential: -+ return "Differential" - } - } - -@@ -43,11 +46,23 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { - } - } - -+// has to be kept in sync with V8 -+enum JITTypeBits: Int { -+ case turbofanB = 1 // 1 << 0 -+ case maglevB = 2 // 1 << 1 -+ case sparkplugB = 4 // 1 << 2 -+} -+ - /// The result of executing a program. - public protocol Execution { -- var outcome: ExecutionOutcome { get } -+ var outcome: ExecutionOutcome { get set } - var stdout: String { get } - var stderr: String { get } - var fuzzout: String { get } -- var execTime: TimeInterval { get } -+ var execTime: TimeInterval { get set } -+ var compilersUsed: [JITType] { get set } -+ var unOptStdout: String? { get set } -+ var optStdout: String? { get set } -+ var reproducesInNonReplMode: Bool? { get set } -+ var bugOracleTime: TimeInterval? { get set } - } -diff --git a/Sources/Fuzzilli/Execution/REPRL.swift b/Sources/Fuzzilli/Execution/REPRL.swift -index 185d1f8..1ec60d4 100644 ---- a/Sources/Fuzzilli/Execution/REPRL.swift -+++ b/Sources/Fuzzilli/Execution/REPRL.swift -@@ -19,7 +19,7 @@ import libreprl - /// scripts, but resets the global state in between executions. - public class REPRL: ComponentBase, ScriptRunner { - /// Kill and restart the child process after this many script executions -- private let maxExecsBeforeRespawn: Int -+ public let maxExecsBeforeRespawn: Int - - /// Commandline arguments for the executable - public private(set) var processArguments: [String] -@@ -79,7 +79,7 @@ public class REPRL: ComponentBase, ScriptRunner { - env.append(key + "=" + value) - } - -- public func run(_ script: String, withTimeout timeout: UInt32) -> Execution { -+ public func run(_ script: String, withTimeout timeout: UInt32, differentialFuzzingPositionDumpSeed: UInt32) -> Execution { - // Log the current script into the buffer if diagnostics are enabled. - if fuzzer.config.enableDiagnostics { - self.scriptBuffer += script + "\n" -@@ -108,8 +108,11 @@ public class REPRL: ComponentBase, ScriptRunner { - var execTime: UInt64 = 0 // In microseconds - let timeout = UInt64(timeout) * 1000 // In microseconds - var status: Int32 = 0 -+ var encodedJitState: UInt8 = 0 - script.withCString { -- status = reprl_execute(reprlContext, $0, UInt64(script.count), UInt64(timeout), &execTime, freshInstance) -+ status = reprl_execute(reprlContext, $0, UInt64(script.count), UInt64(timeout), &execTime, freshInstance, -+ differentialFuzzingPositionDumpSeed, &encodedJitState) -+ - // 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 { -@@ -118,7 +121,9 @@ public class REPRL: ComponentBase, ScriptRunner { - fuzzer.dispatchEvent(fuzzer.events.DiagnosticsEvent, data: (name: "REPRLFail", content: scriptBuffer)) - } - Thread.sleep(forTimeInterval: 1) -- status = reprl_execute(reprlContext, $0, UInt64(script.count), UInt64(timeout), &execTime, 1) -+ status = reprl_execute(reprlContext, $0, UInt64(script.count), UInt64(timeout), &execTime, 1, -+ differentialFuzzingPositionDumpSeed, &encodedJitState) -+ - } - } - -@@ -150,6 +155,16 @@ public class REPRL: ComponentBase, ScriptRunner { - } - execution.execTime = Double(execTime) / 1_000_000 - -+ if encodedJitState & UInt8(JITTypeBits.turbofanB.rawValue) != 0 { -+ execution.compilersUsed.append(.turbofan) -+ } -+ if encodedJitState & UInt8(JITTypeBits.maglevB.rawValue) != 0 { -+ execution.compilersUsed.append(.maglev) -+ } -+ if encodedJitState & UInt8(JITTypeBits.sparkplugB.rawValue) != 0 { -+ execution.compilersUsed.append(.sparkplug) -+ } -+ - return execution - } - } -@@ -163,7 +178,12 @@ class REPRLExecution: Execution { - private let execId: Int - - var outcome = ExecutionOutcome.succeeded -+ var compilersUsed: [JITType] = [] - var execTime: TimeInterval = 0 -+ var unOptStdout: String? = nil -+ var optStdout: String? = nil -+ var reproducesInNonReplMode: Bool? = nil -+ var bugOracleTime: TimeInterval? = nil - - init(from reprl: REPRL) { - self.reprl = reprl -@@ -178,8 +198,14 @@ class REPRLExecution: Execution { - - var stdout: String { - assert(outputStreamsAreValid) -+ let x = String(cString: reprl_fetch_stdout(reprl.reprlContext)) - if cachedStdout == nil { - cachedStdout = String(cString: reprl_fetch_stdout(reprl.reprlContext)) -+ } else if (cachedStdout!) != x { -+ print(cachedStdout!) -+ print("-----------------------------------") -+ print(x) -+ fatalError("repl is bricked!") - } - return cachedStdout! - } -diff --git a/Sources/Fuzzilli/Execution/ScriptRunner.swift b/Sources/Fuzzilli/Execution/ScriptRunner.swift -index 36bccf7..8a7ee2d 100644 ---- a/Sources/Fuzzilli/Execution/ScriptRunner.swift -+++ b/Sources/Fuzzilli/Execution/ScriptRunner.swift -@@ -16,7 +16,7 @@ public protocol ScriptRunner: Component { - var processArguments: [String] { get } - - /// Executes a script, waits for it to complete, and returns the result. -- func run(_ script: String, withTimeout timeout: UInt32) -> Execution -+ func run(_ script: String, withTimeout timeout: UInt32, differentialFuzzingPositionDumpSeed: UInt32) -> Execution - - /// Sets an environment variable for the child process. Must only be called before initialization. - func setEnvironmentVariable(_ key: String, to value: String) -diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift -index b854f63..dc93021 100644 ---- a/Sources/Fuzzilli/Fuzzer.swift -+++ b/Sources/Fuzzilli/Fuzzer.swift -@@ -14,6 +14,14 @@ - - import Foundation - -+ -+fileprivate let prependJS = try! String(contentsOfFile: "prepend.js") -+fileprivate let B = 1; -+fileprivate let KB = 1024 * B; -+fileprivate let MB = 1024 * KB; -+ -+fileprivate let execPoison = ["(see crbug.com/", "Aborting on ", "Fatal JavaScript out of memory:"]; -+ - public class Fuzzer { - /// Id of this fuzzer. - public let id: UUID -@@ -36,6 +44,9 @@ public class Fuzzer { - /// The script runner used to execute generated scripts. - public let runner: ScriptRunner - -+ /// The script runners used to compare against in differential executions. -+ public let referenceRunner: ScriptRunner -+ - /// The fuzzer engine producing new programs from existing ones and executing them. - public let engine: FuzzEngine - -@@ -63,6 +74,8 @@ public class Fuzzer { - /// The minimizer to shrink programs that cause crashes or trigger new interesting behaviour. - public let minimizer: Minimizer - -+ private let localId: UInt32 -+ - /// The engine used for initial corpus generation (if performed). - public let corpusGenerationEngine = GenerativeEngine() - -@@ -155,9 +168,9 @@ public class Fuzzer { - - /// Constructs a new fuzzer instance with the provided components. - public init( -- configuration: Configuration, scriptRunner: ScriptRunner, engine: FuzzEngine, mutators: WeightedList, -+ configuration: Configuration, scriptRunner: ScriptRunner, referenceRunner: ScriptRunner, engine: FuzzEngine, mutators: WeightedList, - codeGenerators: WeightedList, programTemplates: WeightedList, evaluator: ProgramEvaluator, -- environment: Environment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, queue: DispatchQueue? = nil -+ environment: Environment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, localId: UInt32, queue: DispatchQueue? = nil - ) { - let uniqueId = UUID() - self.id = uniqueId -@@ -175,9 +188,13 @@ public class Fuzzer { - self.lifter = lifter - self.corpus = corpus - self.runner = scriptRunner -+ self.referenceRunner = referenceRunner - self.minimizer = minimizer -+ self.localId = localId - self.logger = Logger(withLabel: "Fuzzer") - -+ // self.removeMetadataFilesIfExist() -+ - // Register this fuzzer instance with its queue so that it is possible to - // obtain a reference to the Fuzzer instance when running on its queue. - // This creates a reference cycle, but Fuzzer instances aren't expected -@@ -185,6 +202,36 @@ public class Fuzzer { - self.queue.setSpecific(key: Fuzzer.dispatchQueueKey, value: self) - } - -+ private func jitMetadataFileURL(_ seed: UInt32) -> URL { -+ let jitMetadataFileName = String(format: "%u_position_dump.json", seed) -+ return URL(fileURLWithPath: "/tmp").appendingPathComponent(jitMetadataFileName) -+ } -+ -+ private func outputMetadataFileURL(_ seed: UInt32) -> URL { -+ let jitMetadataFileName = String(format: "%u_output_dump.txt", seed) -+ return URL(fileURLWithPath: "/tmp").appendingPathComponent(jitMetadataFileName) -+ } -+ -+ private func jitMetadataFileExists(_ seed: UInt32) -> Bool { -+ return FileManager.default.fileExists(atPath: self.jitMetadataFileURL(seed).path) -+ } -+ -+ private func outputMetadataFileExists(_ seed: UInt32) -> Bool { -+ return FileManager.default.fileExists(atPath: self.outputMetadataFileURL(seed).path) -+ } -+ -+ -+ private func removeMetadataFilesIfExist(_ seed: UInt32) { -+ if self.jitMetadataFileExists(seed) { -+ let fileURL = jitMetadataFileURL(seed); -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ } -+ if self.outputMetadataFileExists(seed) { -+ let fileURL = outputMetadataFileURL(seed); -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ } -+ } -+ - /// Returns the fuzzer for the active DispatchQueue. - public static var current: Fuzzer? { - return DispatchQueue.getSpecific(key: Fuzzer.dispatchQueueKey) -@@ -235,6 +282,7 @@ public class Fuzzer { - assert(!isInitialized) - - // Initialize the script runner first so we are able to execute programs. -+ referenceRunner.initialize(with: self) - runner.initialize(with: self) - - // Then initialize all components. -@@ -383,6 +431,9 @@ public class Fuzzer { - // from another instance triggers a crash in this instance. - processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) - -+ case .differential: -+ processDifferential(program, withStderr: execution.stderr, withStdout: execution.unOptStdout!, origin: origin, optStdout: execution.optStdout!) -+ - case .succeeded: - var imported = false - if let aspects = evaluator.evaluate(execution) { -@@ -403,6 +454,18 @@ public class Fuzzer { - return execution.outcome - } - -+ public func importDifferential(_ program: Program, origin: ProgramOrigin) { -+ dispatchPrecondition(condition: .onQueue(queue)) -+ let execution = execute(program, purpose: .other) -+ if case .differential = execution.outcome { -+ processDifferential(program, withStderr: execution.stderr, withStdout: execution.unOptStdout!, origin: origin, optStdout: execution.optStdout!) -+ } else { -+ // Non-deterministic differential -+ dispatchEvent(events.DifferentialFound, data: (program, behaviour: .flaky, origin: origin, opt_stdout: "remote import", unopt_stdout: "remote import", reproducesInNonReplMode: false)) -+ } -+ } -+ -+ - /// Imports a crashing program into this fuzzer. - /// - /// Similar to importProgram, but will make sure to generate a CrashFound event even if the crash does not reproduce. -@@ -449,6 +512,133 @@ public class Fuzzer { - return currentCorpusImportJob.progress() - } - -+ public enum DifferentialExecute { -+ case force -+ case disabled -+ case auto -+ } -+ -+ -+ private func formatDate() -> String { -+ let formatter = DateFormatter() -+ formatter.dateFormat = "yyyyMMddHHmmss" -+ return formatter.string(from: Date()) -+ } -+ -+ func crashReproducesWithoutDumping(_ program: Program, _ script: String) -> Bool { -+ // write script to tmp file -+ let filename = "crash_repro_program_\(self.formatDate())_\(program.id).js" -+ let fileURL = URL(fileURLWithPath: "/tmp").appendingPathComponent(filename) -+ -+ do { -+ try script.write(to: fileURL, atomically: false, encoding: String.Encoding.utf8) -+ } catch { -+ logger.error("Failed to write file \(fileURL): \(error)") -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return false -+ } -+ -+ let task = Process() -+ -+ let d8Path = self.runner.processArguments[0] -+ let d8SDumpingFlags = ["--turbofan-dumping", "--generate-dump-positions", "--verify-heap-on-jit-dump", "--maglev-dumping", "--sparkplug-dumping"] -+ let d8FlagsWithoutDumping = self.runner.processArguments.filter { !d8SDumpingFlags.contains($0) && $0 != d8Path } -+ -+ let errorPipe = Pipe() -+ -+ task.executableURL = URL(fileURLWithPath: "/usr/bin/timeout") -+ task.arguments = ["15", d8Path] + d8FlagsWithoutDumping + [fileURL.path] -+ task.standardOutput = FileHandle.nullDevice -+ task.standardError = errorPipe -+ -+ do { -+ try task.run() -+ } catch let error { -+ logger.error(error.localizedDescription) -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return false -+ } -+ -+ task.waitUntilExit() -+ -+ if task.isRunning { -+ task.terminate() -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return false -+ } -+ -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ -+ let stderr = String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: String.Encoding.utf8) -+ -+ if stderr == nil { -+ return false -+ } -+ for p in execPoison { -+ if stderr!.contains(p) { -+ return false -+ } -+ } -+ return task.terminationStatus != 0 && task.terminationStatus != 124 -+ } -+ -+ func differentialReproducesInNonReplMode(_ program: Program, _ script: String, _ differentialFuzzingPositionDumpSeed: UInt32) -> Bool { -+ // write script to tmp file -+ let filename = "program_\(self.formatDate())_\(program.id)_\(differentialFuzzingPositionDumpSeed).js" -+ let fileURL = URL(fileURLWithPath: "/tmp").appendingPathComponent(filename) -+ -+ // also prepend a filter for benign differentials here -+ let prependedScript = prependJS + script -+ -+ do { -+ try prependedScript.write(to: fileURL, atomically: false, encoding: String.Encoding.utf8) -+ } catch { -+ logger.error("Failed to write file \(fileURL): \(error)") -+ return false -+ } -+ -+ let task = Process() -+ -+ let d8Path = self.runner.processArguments[0] -+ -+ task.executableURL = URL(fileURLWithPath: "/usr/bin/timeout") -+ task.arguments = ["15", self.config.relateToolPath!, "--validate", "--d8=\(d8Path)", "--poc=\(fileURL.path)"] -+ task.standardOutput = FileHandle.nullDevice -+ task.standardError = FileHandle.nullDevice -+ -+ do { -+ try task.run() -+ } catch let error { -+ logger.error(error.localizedDescription) -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return false -+ } -+ -+ task.waitUntilExit() -+ -+ if task.isRunning { -+ task.terminate() -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return false -+ } -+ try? FileManager.default.removeItem(atPath: fileURL.path) -+ return task.terminationStatus != 0 && task.terminationStatus != 124 -+ } -+ -+ private func readOutputDump(_ seed: UInt32) -> String? { -+ let filename = "/tmp/\(seed)_output_dump.txt" -+ let fileURL = URL(fileURLWithPath: filename) -+ -+ guard let data = try? Data(contentsOf: fileURL) else { -+ logger.warning("Failed to read output file at \(fileURL)") -+ return nil -+ } -+ -+ let asciiData = Data(data.filter { byte in byte <= 127 }) -+ -+ return String(data: asciiData, encoding: .utf8)! -+ } -+ - /// Executes a program. - /// - /// This will first lift the given FuzzIL program to the target language, then use the configured script runner to execute it. -@@ -457,17 +647,113 @@ public class Fuzzer { - /// - program: The FuzzIL program to execute. - /// - 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. -+ /// - differentialExecute: force disabled or auto (default) - /// - 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, -+ differentialExecute: DifferentialExecute = .auto) -> Execution { - dispatchPrecondition(condition: .onQueue(queue)) - assert(runner.isInitialized) - -- let script = lifter.lift(program) -+ let startTime = Date(); -+ -+ var g = SystemRandomNumberGenerator() -+ -+ // use unique localId for the seed -+ let differentialFuzzingPositionDumpSeed = localId * 100000 + UInt32(Int.random(in: 1...99999, using: &g)); -+ -+ self.removeMetadataFilesIfExist(differentialFuzzingPositionDumpSeed) - -+ let script = lifter.lift(program) - dispatchEvent(events.PreExecute, data: (program, purpose)) -- let execution = runner.run(script, withTimeout: timeout ?? config.timeout) -+ -+ var execution = runner.run(script, withTimeout: timeout ?? config.timeout, -+ differentialFuzzingPositionDumpSeed: differentialFuzzingPositionDumpSeed) - dispatchEvent(events.PostExecute, data: execution) - -+ -+ if execution.execTime * 1000 >= Double((timeout ?? config.timeout) + 500) { -+ logger.warning("execution took longer than expected \(execution.execTime * 1000)") -+ } -+ -+ let isJitExecution = execution.compilersUsed.count >= 1 -+ -+ if isJitExecution && execution.outcome == .succeeded { -+ dispatchEvent(events.JITExecutingProgramFound, data: (program, execution.compilersUsed, true)) -+ } -+ -+ if execution.outcome == .succeeded && isJitExecution && self.jitMetadataFileExists(differentialFuzzingPositionDumpSeed) && -+ differentialExecute != .disabled && purpose != .runtimeAssistedMutation { -+ assert(referenceRunner.isInitialized) -+ -+ // read the file /tmp/{dumpling_seed}_output_dump.txt as a string -+ let opt_stdout = readOutputDump(differentialFuzzingPositionDumpSeed) -+ if opt_stdout == nil { -+ self.removeMetadataFilesIfExist(differentialFuzzingPositionDumpSeed) -+ return execution -+ } -+ -+ let diff = referenceRunner.run(script, withTimeout: (timeout ?? config.timeout) * 2, -+ differentialFuzzingPositionDumpSeed: differentialFuzzingPositionDumpSeed) -+ // sparkplug is enabled in unopt runs so log that usage as well -+ -+ if diff.compilersUsed.contains(.sparkplug) { -+ assert(!diff.compilersUsed.contains(.maglev) && !diff.compilersUsed.contains(.turbofan)) -+ dispatchEvent(events.JITExecutingProgramFound, data: (program, diff.compilersUsed, false)) -+ } -+ -+ dispatchEvent(events.PostExecute, data: diff) -+ -+ if (diff.outcome == .timedOut) { -+ // treat this as a timeout here so that we can -+ execution.outcome = .timedOut -+ } -+ if Double(diff.execTime * 1000) >= Double((timeout ?? config.timeout)*2 + 500) { -+ logger.warning("diff execution took longer than expected \(diff.execTime * 1000)") -+ } -+ -+ // execution.execTime += diff.execTime -+ if (diff.outcome == .succeeded) { -+ let unopt_stdout = readOutputDump(differentialFuzzingPositionDumpSeed) -+ if unopt_stdout == nil { -+ self.removeMetadataFilesIfExist(differentialFuzzingPositionDumpSeed) -+ return execution -+ } -+ execution.unOptStdout = unopt_stdout -+ execution.optStdout = opt_stdout -+ if !relate(opt_stdout!, with: unopt_stdout!) { -+ execution.outcome = .differential -+ execution.reproducesInNonReplMode = differentialReproducesInNonReplMode(program, script, differentialFuzzingPositionDumpSeed) -+ } -+ let now = Date() -+ execution.bugOracleTime = now.timeIntervalSince(startTime) -+ if (execution.bugOracleTime!) * 1000 >= 8000.0 { -+ logger.warning("bugOracle took longer than expected \(execution.bugOracleTime! * 1000)") -+ } -+ dispatchEvent(events.RelationPerformed, data: (program, execution)) -+ } else { -+ // return diff -+ } -+ -+ self.removeMetadataFilesIfExist(differentialFuzzingPositionDumpSeed) -+ } else { -+ self.removeMetadataFilesIfExist(differentialFuzzingPositionDumpSeed) -+ -+ if case .crashed(_) = execution.outcome { -+ var poisoned = false -+ for p in execPoison { -+ if execution.stderr.contains(p) { -+ execution.outcome = .failed(1) -+ poisoned = true -+ } -+ } -+ if !poisoned && !crashReproducesWithoutDumping(program, script) { -+ execution.outcome = .failed(2) -+ } -+ } -+ } -+ -+ // assert(!self.jitMetadataFileExists(differentialFuzzingPositionDumpSeed)) - return execution - } - -@@ -553,11 +839,10 @@ public class Fuzzer { - 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("REFERENCE ARGS: \(referenceRunner.processArguments.joined(separator: " "))\n", at: .footer) - program.comments.add("EXECUTION TIME: \(Int(exectime * 1000))ms", at: .footer) - } - assert(program.comments.at(.footer)?.contains("CRASH INFO") ?? false) -@@ -583,6 +868,38 @@ public class Fuzzer { - } - } - -+ func processDifferential(_ program: Program, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin, optStdout: String) { -+ func processCommon(_ program: Program) { -+ let hasDiffInfo = program.comments.at(.footer)?.contains("DIFFERENTIAL INFO") ?? false -+ if !hasDiffInfo { -+ program.comments.add("DIFFERENTIAL INFO\n==========\n", at: .footer) -+ -+ program.comments.add("STDERR:\n" + stderr, at: .footer) -+ program.comments.add("ARGS: \(runner.processArguments.joined(separator: " "))\n", at: .footer) -+ program.comments.add("REFERENCE ARGS: \(referenceRunner.processArguments.joined(separator: " "))\n", at: .footer) -+ } -+ assert(program.comments.at(.footer)?.contains("DIFFERENTIAL INFO") ?? false) -+ -+ // Check for uniqueness only after minimization -+ let execution = execute(program, withTimeout: self.config.timeout * 2, purpose: .other) -+ if case .differential = execution.outcome { -+ dispatchEvent(events.DifferentialFound, data: (program, .deterministic, origin, optStdout, stdout, execution.reproducesInNonReplMode!)) -+ } else { -+ dispatchEvent(events.DifferentialFound, data: (program, .flaky, origin, optStdout, stdout, false)) -+ } -+ } -+ -+ if !origin.requiresMinimization() { -+ return processCommon(program) -+ } -+ -+ fuzzGroup.enter() -+ minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { minimizedProgram in -+ self.fuzzGroup.leave() -+ processCommon(minimizedProgram) -+ } -+ } -+ - /// Constructs a new ProgramBuilder using this fuzzing context. - public func makeBuilder(forMutating parent: Program? = nil, mode: ProgramBuilder.Mode = .aggressive) -> ProgramBuilder { - dispatchPrecondition(condition: .onQueue(queue)) -@@ -699,20 +1016,6 @@ public class Fuzzer { - return b.finalize() - } - -- // Verifies that the fuzzer is not creating a large number of core dumps -- public func checkCoreFileGeneration() { -- #if os(Linux) -- do { -- let corePattern = try String(contentsOfFile: "/proc/sys/kernel/core_pattern", encoding: String.Encoding.ascii) -- if !corePattern.hasPrefix("|/bin/false") { -- logger.fatal("Please run: sudo sysctl -w 'kernel.core_pattern=|/bin/false'") -- } -- } catch { -- logger.warning("Could not check core dump behaviour. Please ensure core_pattern is set to '|/bin/false'") -- } -- #endif -- } -- - /// Runs a number of startup tests to check whether everything is configured correctly. - public func runStartupTests() { - assert(isInitialized) -@@ -737,6 +1040,7 @@ public class Fuzzer { - let complexProgram = makeComplexProgram() - for _ in 0..<5 { - let execution = execute(complexProgram, purpose: .startup) -+ logger.info("Execution time: \(execution.execTime * 1000)ms") - maxExecutionTime = max(maxExecutionTime, execution.execTime) - } - -@@ -801,7 +1105,7 @@ public class Fuzzer { - - mutating func notifyImportOutcome(_ outcome: ExecutionOutcome) { - switch outcome { -- case .crashed: -+ case .crashed, .differential: - // This is unexpected so we don't track these - break - case .failed: -diff --git a/Sources/Fuzzilli/Modules/Statistics.swift b/Sources/Fuzzilli/Modules/Statistics.swift -index 225cea6..d81f1cf 100644 ---- a/Sources/Fuzzilli/Modules/Statistics.swift -+++ b/Sources/Fuzzilli/Modules/Statistics.swift -@@ -50,6 +50,14 @@ public class Statistics: Module { - /// This is only computed for successful executions, and so excludes e.g. samples that timed out. - private var executionTimeAvg = MovingAverage(n: 1000) - -+ /// Moving average over the cummulative time it takes in the fuzzer to get through a bug oracle run -+ /// This will consider both executions and the time spent in the python script -+ private var cumbugOracleTimeAvg = MovingAverage(n: 1000) -+ -+ private var optDumpSizeAvg = MovingAverage(n: 10000) -+ private var unOptDumpSizeAvg = MovingAverage(n: 10000) -+ -+ - /// Moving average of the number of valid programs in the last 1000 generated programs. - private var correctnessRate = MovingAverage(n: 1000) - -@@ -73,6 +81,9 @@ public class Statistics: Module { - ownData.avgProgramSize = programSizeAvg.currentValue - ownData.avgCorpusProgramSize = corpusProgramSizeAvg.currentValue - ownData.avgExecutionTime = executionTimeAvg.currentValue -+ ownData.avgBugOracleTime = cumbugOracleTimeAvg.currentValue -+ ownData.avgDumpSizeOpt = optDumpSizeAvg.currentValue -+ ownData.avgDumpSizeUnOpt = unOptDumpSizeAvg.currentValue - ownData.fuzzerOverhead = fuzzerOverheadAvg.currentValue - ownData.minimizationOverhead = minimizationOverheadAvg.currentValue - ownData.correctnessRate = correctnessRate.currentValue -@@ -88,6 +99,13 @@ public class Statistics: Module { - data.timedOutSamples += node.timedOutSamples - data.totalExecs += node.totalExecs - -+ data.relationsPerformed += node.relationsPerformed -+ data.sparkplugSamples += node.sparkplugSamples -+ data.maglevSamples += node.maglevSamples -+ data.turbofanSamples += node.turbofanSamples -+ data.jitSamples += node.jitSamples -+ -+ - if !inactiveNodes.contains(id) { - // Add fields that only have meaning for active nodes - -@@ -100,6 +118,9 @@ public class Statistics: Module { - data.avgProgramSize += node.avgProgramSize * numNodesRepresentedByData - data.avgCorpusProgramSize += node.avgCorpusProgramSize * numNodesRepresentedByData - data.avgExecutionTime += node.avgExecutionTime * numNodesRepresentedByData -+ data.avgBugOracleTime += node.avgBugOracleTime * numNodesRepresentedByData -+ data.avgDumpSizeOpt += node.avgDumpSizeOpt * numNodesRepresentedByData -+ data.avgDumpSizeUnOpt += node.avgDumpSizeUnOpt * numNodesRepresentedByData - data.execsPerSecond += node.execsPerSecond - data.fuzzerOverhead += node.fuzzerOverhead * numNodesRepresentedByData - data.minimizationOverhead += node.minimizationOverhead * numNodesRepresentedByData -@@ -116,6 +137,9 @@ public class Statistics: Module { - data.avgProgramSize /= totalNumberOfNodes - data.avgCorpusProgramSize /= totalNumberOfNodes - data.avgExecutionTime /= totalNumberOfNodes -+ data.avgBugOracleTime /= totalNumberOfNodes -+ data.avgDumpSizeOpt /= totalNumberOfNodes -+ data.avgDumpSizeUnOpt /= totalNumberOfNodes - data.fuzzerOverhead /= totalNumberOfNodes - data.minimizationOverhead /= totalNumberOfNodes - data.correctnessRate /= totalNumberOfNodes -@@ -127,6 +151,40 @@ public class Statistics: Module { - public func initialize(with fuzzer: Fuzzer) { - fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { _ in - self.ownData.crashingSamples += 1 -+ -+ } -+ fuzzer.registerEventListener(for: fuzzer.events.JITExecutingProgramFound) { ev in -+ for cu in ev.compilers { -+ if (cu == .turbofan) { -+ self.ownData.turbofanSamples += 1 -+ } else if (cu == .maglev) { -+ self.ownData.maglevSamples += 1 -+ } else { -+ assert(cu == .sparkplug) -+ self.ownData.sparkplugSamples += 1 -+ } -+ } -+ if (ev.is_optimizing) { -+ assert(!ev.compilers.contains(.sparkplug)) -+ self.ownData.jitSamples += 1 -+ } -+ } -+ fuzzer.registerEventListener(for: fuzzer.events.RelationPerformed) { ev in -+ self.cumbugOracleTimeAvg.add(ev.execution.bugOracleTime!) -+ self.optDumpSizeAvg.add(ev.execution.optStdout!.count) -+ self.unOptDumpSizeAvg.add(ev.execution.unOptStdout!.count) -+ -+ self.ownData.relationsPerformed += 1 -+ } -+ fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { ev in -+ if (ev.reproducesInNonReplMode) { -+ self.ownData.differentialSamples += 1 -+ } -+ /* -+ if self.ownData.differentialSamples > 200 { -+ fatalError("Found more than 200 differentials, stopping") -+ } -+ */ - } - fuzzer.registerEventListener(for: fuzzer.events.TimeOutFound) { _ in - self.ownData.timedOutSamples += 1 -@@ -164,6 +222,7 @@ public class Statistics: Module { - let totalTime = now.timeIntervalSince(self.lastExecDate) - self.lastExecDate = now - -+ - let overhead = 1.0 - (exec.execTime / totalTime) - self.fuzzerOverheadAvg.add(overhead) - } -diff --git a/Sources/Fuzzilli/Modules/Storage.swift b/Sources/Fuzzilli/Modules/Storage.swift -index 3600507..40581cd 100644 ---- a/Sources/Fuzzilli/Modules/Storage.swift -+++ b/Sources/Fuzzilli/Modules/Storage.swift -@@ -19,6 +19,7 @@ public class Storage: Module { - private let storageDir: String - private let crashesDir: String - private let duplicateCrashesDir: String -+ private let differentialsDir: String - private let corpusDir: String - private let statisticsDir: String - private let stateFile: String -@@ -35,6 +36,7 @@ public class Storage: Module { - self.storageDir = storageDir - self.crashesDir = storageDir + "/crashes" - self.duplicateCrashesDir = storageDir + "/crashes/duplicates" -+ self.differentialsDir = storageDir + "/differentials" - self.corpusDir = storageDir + "/corpus" - self.failedDir = storageDir + "/failed" - self.timeOutDir = storageDir + "/timeouts" -@@ -52,6 +54,7 @@ public class Storage: Module { - 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) - if fuzzer.config.enableDiagnostics { -@@ -95,6 +98,21 @@ public class Storage: Module { - } - } - -+ fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { ev in -+ let filename = "program_\(self.formatDate())_\(ev.program.id)_\(ev.behaviour.rawValue)" -+ var storeDir: String; -+ if (ev.reproducesInNonReplMode) { -+ storeDir = self.differentialsDir -+ } else { -+ return -+ } -+ -+ self.storeProgram(ev.program, as: filename, in: storeDir) -+ if ev.opt_stdout != nil { -+ self.storeDifferentialDump(ev.opt_stdout!, and: ev.unopt_stdout, as: filename, in: storeDir) -+ } -+ } -+ - fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { ev in - let filename = "program_\(self.formatDate())_\(ev.program.id)" - self.storeProgram(ev.program, as: filename, in: self.corpusDir) -@@ -103,7 +121,7 @@ public class Storage: Module { - if fuzzer.config.enableDiagnostics { - fuzzer.registerEventListener(for: fuzzer.events.DiagnosticsEvent) { ev in - let filename = "\(self.formatDate())_\(ev.name)_\(String(currentMillis()))" -- let url = URL(fileURLWithPath: self.diagnosticsDir + filename + ".diag") -+ let url = URL(fileURLWithPath: self.diagnosticsDir + "/" + filename + ".diag") - self.createFile(url, withContent: ev.content) - } - -@@ -144,6 +162,13 @@ public class Storage: Module { - } - } - -+ private func storeDifferentialDump(_ opt: String, and unopt: String, as filename: String, in directory: String) { -+ let opt_url = URL(fileURLWithPath: "\(directory)/\(filename)_opt.txt") -+ let unopt_url = URL(fileURLWithPath: "\(directory)/\(filename)_unopt.txt") -+ createFile(opt_url, withContent: opt) -+ createFile(unopt_url, withContent: unopt) -+ } -+ - private func storeProgram(_ program: Program, as filename: String, in directory: String) { - // Always include comments when writing programs to disk - let options = LiftingOptions.includeComments -diff --git a/Sources/Fuzzilli/Modules/Sync.swift b/Sources/Fuzzilli/Modules/Sync.swift -index 241b5f4..dbf074e 100644 ---- a/Sources/Fuzzilli/Modules/Sync.swift -+++ b/Sources/Fuzzilli/Modules/Sync.swift -@@ -83,6 +83,10 @@ enum MessageType: UInt32 { - - // Log messages are forwarded from child to parent nides. - case log = 6 -+ -+ // A program that caused a differential. -+ // Only sent from a children to their parent. -+ case differentialProgram = 7 - } - - /// Distributed fuzzing nodes can be configured to only share their corpus in one direction in the tree. -@@ -243,6 +247,15 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { - logger.warning("Received malformed program from child node: \(error)") - } - -+ case .differentialProgram: -+ do { -+ let proto = try Fuzzilli_Protobuf_Program(serializedData: data) -+ let program = try Program(from: proto) -+ fuzzer.importDifferential(program, origin: .child(id: child)) -+ } catch { -+ logger.warning("Received malformed program from child node: \(error)") -+ } -+ - 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.") -@@ -357,6 +370,10 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { - self.sendProgram(ev.program, as: .crashingProgram) - } - -+ fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { ev in -+ self.sendProgram(ev.program, as: .differentialProgram) -+ } -+ - fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in - if !self.parentIsShuttingDown { - let shutdownGroup = DispatchGroup() -@@ -390,6 +407,26 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { - } - } - -+ // remove every *_output_dump.txt and *_position_dump.json that are older than 5mins -+ fuzzer.timers.scheduleTask(every: 10 * Minutes) { -+ let dumpFilesRegex = try! Regex("^\\d+_(output|position)_dump\\.(txt|json)$") -+ -+ let items = try! FileManager.default.contentsOfDirectory(atPath: "/tmp") -+ -+ for item in items { -+ if item.contains(dumpFilesRegex) { -+ do { -+ let itemPath = "/tmp/\(item)"; -+ let attr = try FileManager.default.attributesOfItem(atPath: itemPath) -+ let date = attr[FileAttributeKey.modificationDate] as? Date -+ if (-(date!.timeIntervalSinceNow) >= 5 * Minutes) { -+ try? FileManager.default.removeItem(atPath: itemPath) -+ } -+ } catch {} -+ } -+ } -+ } -+ - // Forward log events to our parent node. - fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in - let msg = Fuzzilli_Protobuf_LogMessage.with { -@@ -461,6 +498,7 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { - } - - case .crashingProgram, -+ .differentialProgram, - .statistics, - .log: - logger.error("Received unexpected message: \(messageType)") -@@ -468,7 +506,7 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { - } - - private func sendProgram(_ program: Program, as type: MessageType) { -- assert(type == .interestingProgram || type == .crashingProgram) -+ assert(type == .interestingProgram || type == .crashingProgram || type == .differentialProgram) - let proto = program.asProtobuf() - guard let payload = try? proto.serializedData() else { - return logger.error("Failed to serialize program") -diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift -index 67498ea..1926cf4 100644 ---- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift -+++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift -@@ -89,7 +89,7 @@ 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, differentialExecute: .disabled) - 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. -@@ -114,6 +114,8 @@ public class RuntimeAssistedMutator: Mutator { - case .succeeded: - // The expected case. - break -+ case .differential: -+ fatalError("Differential result impossible") - } - - // Process the output to build the mutated program. -diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift -index f01037f..f40ff9b 100644 ---- a/Sources/Fuzzilli/Protobuf/operations.pb.swift -+++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift -@@ -72,7 +72,7 @@ public enum Fuzzilli_Protobuf_PropertyType: SwiftProtobuf.Enum { - - extension Fuzzilli_Protobuf_PropertyType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. -- public static let allCases: [Fuzzilli_Protobuf_PropertyType] = [ -+ public static var allCases: [Fuzzilli_Protobuf_PropertyType] = [ - .value, - .getter, - .setter, -@@ -132,7 +132,7 @@ public enum Fuzzilli_Protobuf_UnaryOperator: SwiftProtobuf.Enum { - - extension Fuzzilli_Protobuf_UnaryOperator: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. -- public static let allCases: [Fuzzilli_Protobuf_UnaryOperator] = [ -+ public static var allCases: [Fuzzilli_Protobuf_UnaryOperator] = [ - .preInc, - .preDec, - .postInc, -@@ -214,7 +214,7 @@ public enum Fuzzilli_Protobuf_BinaryOperator: SwiftProtobuf.Enum { - - extension Fuzzilli_Protobuf_BinaryOperator: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. -- public static let allCases: [Fuzzilli_Protobuf_BinaryOperator] = [ -+ public static var allCases: [Fuzzilli_Protobuf_BinaryOperator] = [ - .add, - .sub, - .mul, -@@ -284,7 +284,7 @@ public enum Fuzzilli_Protobuf_Comparator: SwiftProtobuf.Enum { - - extension Fuzzilli_Protobuf_Comparator: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. -- public static let allCases: [Fuzzilli_Protobuf_Comparator] = [ -+ public static var allCases: [Fuzzilli_Protobuf_Comparator] = [ - .equal, - .strictEqual, - .notEqual, -@@ -1561,6 +1561,16 @@ public struct Fuzzilli_Protobuf_Return { - public init() {} - } - -+public struct Fuzzilli_Protobuf_DifferentialHash { -+ // 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_Yield { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for -@@ -2511,192 +2521,6 @@ public struct Fuzzilli_Protobuf_Print { - public init() {} - } - --#if swift(>=5.5) && canImport(_Concurrency) --extension Fuzzilli_Protobuf_PropertyType: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UnaryOperator: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BinaryOperator: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Comparator: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Parameters: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadInteger: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadBigInt: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadFloat: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadString: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadBoolean: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadUndefined: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadNull: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadThis: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadArguments: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadRegExp: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginObjectLiteral: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ObjectLiteralAddProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ObjectLiteralAddElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ObjectLiteralCopyProperties: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ObjectLiteralSetPrototype: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginObjectLiteralMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndObjectLiteralMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndObjectLiteralComputedMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginObjectLiteralGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndObjectLiteralGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginObjectLiteralSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndObjectLiteralSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndObjectLiteral: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassDefinition: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassConstructor: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassConstructor: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddInstanceProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddInstanceElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassInstanceMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassInstanceMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassInstanceGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassInstanceGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassInstanceSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassInstanceSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddStaticProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddStaticElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassStaticInitializer: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassStaticInitializer: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassStaticMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassStaticMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassStaticGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassStaticGetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassStaticSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassStaticSetter: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassPrivateInstanceMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassPrivateStaticMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndClassDefinition: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CreateArray: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CreateIntArray: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CreateFloatArray: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CreateTemplateString: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CreateArrayWithSpread: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadBuiltin: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UpdateProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DeleteProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ConfigureProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UpdateElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DeleteElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ConfigureElement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UpdateComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DeleteComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ConfigureComputedProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_TypeOf: @unchecked Sendable {} --extension Fuzzilli_Protobuf_TestInstanceOf: @unchecked Sendable {} --extension Fuzzilli_Protobuf_TestIn: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginPlainFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndPlainFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginArrowFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndArrowFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginGeneratorFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndGeneratorFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginAsyncFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndAsyncFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginAsyncArrowFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndAsyncArrowFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginAsyncGeneratorFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndAsyncGeneratorFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginConstructor: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndConstructor: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Return: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Yield: @unchecked Sendable {} --extension Fuzzilli_Protobuf_YieldEach: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Await: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallFunction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallFunctionWithSpread: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Construct: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ConstructWithSpread: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallMethodWithSpread: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallComputedMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallComputedMethodWithSpread: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UnaryOperation: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BinaryOperation: @unchecked Sendable {} --extension Fuzzilli_Protobuf_TernaryOperation: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Update: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Dup: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Reassign: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DestructArray: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DestructArrayAndReassign: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DestructObject: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DestructObjectAndReassign: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Compare: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadNamedVariable: @unchecked Sendable {} --extension Fuzzilli_Protobuf_StoreNamedVariable: @unchecked Sendable {} --extension Fuzzilli_Protobuf_DefineNamedVariable: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Eval: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallSuperConstructor: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallSuperMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetPrivateProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetPrivateProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UpdatePrivateProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_CallPrivateMethod: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetSuperProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetSuperProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_GetComputedSuperProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SetComputedSuperProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_UpdateSuperProperty: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoadNewTarget: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Explore: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Probe: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Fixup: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginWith: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndWith: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginIf: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginElse: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndIf: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginSwitch: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginSwitchCase: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginSwitchDefaultCase: @unchecked Sendable {} --extension Fuzzilli_Protobuf_SwitchBreak: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndSwitchCase: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndSwitch: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginWhileLoopHeader: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginWhileLoopBody: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndWhileLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginDoWhileLoopBody: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginDoWhileLoopHeader: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndDoWhileLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForLoopInitializer: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForLoopCondition: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForLoopAfterthought: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForLoopBody: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndForLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForInLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndForInLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForOfLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginForOfLoopWithDestruct: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndForOfLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginRepeatLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndRepeatLoop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoopBreak: @unchecked Sendable {} --extension Fuzzilli_Protobuf_LoopContinue: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginTry: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginCatch: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginFinally: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndTryCatch: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndTryCatchFinally: @unchecked Sendable {} --extension Fuzzilli_Protobuf_ThrowException: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginCodeString: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndCodeString: @unchecked Sendable {} --extension Fuzzilli_Protobuf_BeginBlockStatement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_EndBlockStatement: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Nop: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Print: @unchecked Sendable {} --#endif // swift(>=5.5) && canImport(_Concurrency) -- - // MARK: - Code below here is support for the SwiftProtobuf runtime. - - fileprivate let _protobuf_package = "fuzzilli.protobuf" -@@ -2764,12 +2588,9 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.decodeSingularUInt32Field(value: &self.count) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRest_p) }() -+ case 1: try decoder.decodeSingularUInt32Field(value: &self.count) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasRest_p) - default: break - } - } -@@ -2801,11 +2622,8 @@ extension Fuzzilli_Protobuf_LoadInteger: SwiftProtobuf.Message, SwiftProtobuf._M - - 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.decodeSingularInt64Field(value: &self.value) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.value) - default: break - } - } -@@ -2833,11 +2651,8 @@ extension Fuzzilli_Protobuf_LoadBigInt: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.decodeSingularInt64Field(value: &self.value) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.value) - default: break - } - } -@@ -2865,11 +2680,8 @@ extension Fuzzilli_Protobuf_LoadFloat: SwiftProtobuf.Message, SwiftProtobuf._Mes - - 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.decodeSingularDoubleField(value: &self.value) }() -+ case 1: try decoder.decodeSingularDoubleField(value: &self.value) - default: break - } - } -@@ -2897,11 +2709,8 @@ extension Fuzzilli_Protobuf_LoadString: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.value) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.value) - default: break - } - } -@@ -2929,11 +2738,8 @@ extension Fuzzilli_Protobuf_LoadBoolean: SwiftProtobuf.Message, SwiftProtobuf._M - - 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.value) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.value) - default: break - } - } -@@ -3038,12 +2844,9 @@ extension Fuzzilli_Protobuf_LoadRegExp: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.pattern) }() -- case 2: try { try decoder.decodeSingularUInt32Field(value: &self.flags) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.pattern) -+ case 2: try decoder.decodeSingularUInt32Field(value: &self.flags) - default: break - } - } -@@ -3094,11 +2897,8 @@ extension Fuzzilli_Protobuf_ObjectLiteralAddProperty: SwiftProtobuf.Message, Swi - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -3126,11 +2926,8 @@ extension Fuzzilli_Protobuf_ObjectLiteralAddElement: SwiftProtobuf.Message, Swif - - 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.decodeSingularInt64Field(value: &self.index) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) - default: break - } - } -@@ -3216,28 +3013,21 @@ extension Fuzzilli_Protobuf_BeginObjectLiteralMethod: SwiftProtobuf.Message, Swi - - 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 decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -3276,24 +3066,17 @@ extension Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod: SwiftProtobuf.Mess - - 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) }() -+ case 1: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -3331,11 +3114,8 @@ extension Fuzzilli_Protobuf_BeginObjectLiteralGetter: SwiftProtobuf.Message, Swi - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -3382,11 +3162,8 @@ extension Fuzzilli_Protobuf_BeginObjectLiteralSetter: SwiftProtobuf.Message, Swi - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -3452,11 +3229,8 @@ extension Fuzzilli_Protobuf_BeginClassDefinition: SwiftProtobuf.Message, SwiftPr - - 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.hasSuperclass_p) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.hasSuperclass_p) - default: break - } - } -@@ -3484,24 +3258,17 @@ extension Fuzzilli_Protobuf_BeginClassConstructor: SwiftProtobuf.Message, SwiftP - - 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) }() -+ case 1: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -3540,12 +3307,9 @@ extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, Swi - - 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) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3578,12 +3342,9 @@ extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, Swif - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3615,11 +3376,8 @@ extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Mess - - 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.hasValue_p) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3648,28 +3406,21 @@ extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, Swi - - 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 decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -3708,11 +3459,8 @@ extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, Swi - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -3759,11 +3507,8 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -3811,12 +3556,9 @@ extension Fuzzilli_Protobuf_ClassAddStaticProperty: SwiftProtobuf.Message, Swift - - 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) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3849,12 +3591,9 @@ extension Fuzzilli_Protobuf_ClassAddStaticElement: SwiftProtobuf.Message, SwiftP - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3886,11 +3625,8 @@ extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: SwiftProtobuf.Messag - - 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.hasValue_p) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -3957,28 +3693,21 @@ extension Fuzzilli_Protobuf_BeginClassStaticMethod: SwiftProtobuf.Message, Swift - - 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 decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -4017,11 +3746,8 @@ extension Fuzzilli_Protobuf_BeginClassStaticGetter: SwiftProtobuf.Message, Swift - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -4068,11 +3794,8 @@ extension Fuzzilli_Protobuf_BeginClassStaticSetter: SwiftProtobuf.Message, Swift - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -4120,12 +3843,9 @@ extension Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: SwiftProtobuf.Messa - - 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) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -4158,28 +3878,21 @@ extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: SwiftProtobuf.Messa - - 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 decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -4219,12 +3932,9 @@ extension Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: SwiftProtobuf.Message - - 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) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasValue_p) - default: break - } - } -@@ -4257,28 +3967,21 @@ extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: SwiftProtobuf.Message - - 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 decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -4355,11 +4058,8 @@ extension Fuzzilli_Protobuf_CreateIntArray: SwiftProtobuf.Message, SwiftProtobuf - - 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.decodeRepeatedInt64Field(value: &self.values) }() -+ case 1: try decoder.decodeRepeatedInt64Field(value: &self.values) - default: break - } - } -@@ -4387,11 +4087,8 @@ extension Fuzzilli_Protobuf_CreateFloatArray: SwiftProtobuf.Message, SwiftProtob - - 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.decodeRepeatedDoubleField(value: &self.values) }() -+ case 1: try decoder.decodeRepeatedDoubleField(value: &self.values) - default: break - } - } -@@ -4419,11 +4116,8 @@ extension Fuzzilli_Protobuf_CreateTemplateString: SwiftProtobuf.Message, SwiftPr - - 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.decodeRepeatedStringField(value: &self.parts) }() -+ case 1: try decoder.decodeRepeatedStringField(value: &self.parts) - default: break - } - } -@@ -4451,11 +4145,8 @@ extension Fuzzilli_Protobuf_CreateArrayWithSpread: SwiftProtobuf.Message, SwiftP - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -+ case 1: try decoder.decodeRepeatedBoolField(value: &self.spreads) - default: break - } - } -@@ -4483,11 +4174,8 @@ extension Fuzzilli_Protobuf_LoadBuiltin: SwiftProtobuf.Message, SwiftProtobuf._M - - 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.builtinName) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.builtinName) - default: break - } - } -@@ -4516,12 +4204,9 @@ extension Fuzzilli_Protobuf_GetProperty: SwiftProtobuf.Message, SwiftProtobuf._M - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -4553,11 +4238,8 @@ extension Fuzzilli_Protobuf_SetProperty: SwiftProtobuf.Message, SwiftProtobuf._M - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -4586,12 +4268,9 @@ extension Fuzzilli_Protobuf_UpdateProperty: SwiftProtobuf.Message, SwiftProtobuf - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -4624,12 +4303,9 @@ extension Fuzzilli_Protobuf_DeleteProperty: SwiftProtobuf.Message, SwiftProtobuf - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -4665,15 +4341,12 @@ extension Fuzzilli_Protobuf_ConfigureProperty: SwiftProtobuf.Message, SwiftProto - - 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.isWritable) }() -- case 3: try { try decoder.decodeSingularBoolField(value: &self.isConfigurable) }() -- case 4: try { try decoder.decodeSingularBoolField(value: &self.isEnumerable) }() -- case 5: try { try decoder.decodeSingularEnumField(value: &self.type) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isWritable) -+ case 3: try decoder.decodeSingularBoolField(value: &self.isConfigurable) -+ case 4: try decoder.decodeSingularBoolField(value: &self.isEnumerable) -+ case 5: try decoder.decodeSingularEnumField(value: &self.type) - default: break - } - } -@@ -4718,12 +4391,9 @@ extension Fuzzilli_Protobuf_GetElement: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -4755,11 +4425,8 @@ extension Fuzzilli_Protobuf_SetElement: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.decodeSingularInt64Field(value: &self.index) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) - default: break - } - } -@@ -4788,12 +4455,9 @@ extension Fuzzilli_Protobuf_UpdateElement: SwiftProtobuf.Message, SwiftProtobuf. - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -4826,12 +4490,9 @@ extension Fuzzilli_Protobuf_DeleteElement: SwiftProtobuf.Message, SwiftProtobuf. - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -4867,15 +4528,12 @@ extension Fuzzilli_Protobuf_ConfigureElement: SwiftProtobuf.Message, SwiftProtob - - 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.decodeSingularInt64Field(value: &self.index) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isWritable) }() -- case 3: try { try decoder.decodeSingularBoolField(value: &self.isConfigurable) }() -- case 4: try { try decoder.decodeSingularBoolField(value: &self.isEnumerable) }() -- case 5: try { try decoder.decodeSingularEnumField(value: &self.type) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.index) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isWritable) -+ case 3: try decoder.decodeSingularBoolField(value: &self.isConfigurable) -+ case 4: try decoder.decodeSingularBoolField(value: &self.isEnumerable) -+ case 5: try decoder.decodeSingularEnumField(value: &self.type) - default: break - } - } -@@ -4919,11 +4577,8 @@ extension Fuzzilli_Protobuf_GetComputedProperty: SwiftProtobuf.Message, SwiftPro - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -4970,11 +4625,8 @@ extension Fuzzilli_Protobuf_UpdateComputedProperty: SwiftProtobuf.Message, Swift - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -5002,11 +4654,8 @@ extension Fuzzilli_Protobuf_DeleteComputedProperty: SwiftProtobuf.Message, Swift - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5037,14 +4686,11 @@ extension Fuzzilli_Protobuf_ConfigureComputedProperty: SwiftProtobuf.Message, Sw - - 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.isWritable) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isConfigurable) }() -- case 3: try { try decoder.decodeSingularBoolField(value: &self.isEnumerable) }() -- case 4: try { try decoder.decodeSingularEnumField(value: &self.type) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isWritable) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isConfigurable) -+ case 3: try decoder.decodeSingularBoolField(value: &self.isEnumerable) -+ case 4: try decoder.decodeSingularEnumField(value: &self.type) - default: break - } - } -@@ -5142,25 +4788,18 @@ extension Fuzzilli_Protobuf_BeginPlainFunction: SwiftProtobuf.Message, SwiftProt - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5203,25 +4842,18 @@ extension Fuzzilli_Protobuf_BeginArrowFunction: SwiftProtobuf.Message, SwiftProt - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5264,25 +4896,18 @@ extension Fuzzilli_Protobuf_BeginGeneratorFunction: SwiftProtobuf.Message, Swift - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5325,25 +4950,18 @@ extension Fuzzilli_Protobuf_BeginAsyncFunction: SwiftProtobuf.Message, SwiftProt - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5386,25 +5004,18 @@ extension Fuzzilli_Protobuf_BeginAsyncArrowFunction: SwiftProtobuf.Message, Swif - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5447,25 +5058,18 @@ extension Fuzzilli_Protobuf_BeginAsyncGeneratorFunction: SwiftProtobuf.Message, - - 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) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isStrict) }() -+ case 1: try decoder.decodeSingularMessageField(value: &self._parameters) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isStrict) - 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - if self.isStrict != false { - try visitor.visitSingularBoolField(value: self.isStrict, fieldNumber: 2) - } -@@ -5507,24 +5111,17 @@ extension Fuzzilli_Protobuf_BeginConstructor: SwiftProtobuf.Message, SwiftProtob - - 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) }() -+ case 1: 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 { -+ if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) -- } }() -+ } - try unknownFields.traverse(visitor: &visitor) - } - -@@ -5573,6 +5170,25 @@ extension Fuzzilli_Protobuf_Return: SwiftProtobuf.Message, SwiftProtobuf._Messag - } - } - -+extension Fuzzilli_Protobuf_DifferentialHash: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { -+ public static let protoMessageName: String = _protobuf_package + ".DifferentialHash" -+ public static let _protobuf_nameMap = SwiftProtobuf._NameMap() -+ -+ public mutating func decodeMessage(decoder: inout D) throws { -+ while let _ = try decoder.nextFieldNumber() { -+ } -+ } -+ -+ public func traverse(visitor: inout V) throws { -+ try unknownFields.traverse(visitor: &visitor) -+ } -+ -+ public static func ==(lhs: Fuzzilli_Protobuf_DifferentialHash, rhs: Fuzzilli_Protobuf_DifferentialHash) -> Bool { -+ if lhs.unknownFields != rhs.unknownFields {return false} -+ return true -+ } -+} -+ - extension Fuzzilli_Protobuf_Yield: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".Yield" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() -@@ -5638,11 +5254,8 @@ extension Fuzzilli_Protobuf_CallFunction: SwiftProtobuf.Message, SwiftProtobuf._ - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5671,12 +5284,9 @@ extension Fuzzilli_Protobuf_CallFunctionWithSpread: SwiftProtobuf.Message, Swift - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeRepeatedBoolField(value: &self.spreads) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5708,11 +5318,8 @@ extension Fuzzilli_Protobuf_Construct: SwiftProtobuf.Message, SwiftProtobuf._Mes - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5741,12 +5348,9 @@ extension Fuzzilli_Protobuf_ConstructWithSpread: SwiftProtobuf.Message, SwiftPro - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeRepeatedBoolField(value: &self.spreads) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5779,12 +5383,9 @@ extension Fuzzilli_Protobuf_CallMethod: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5818,13 +5419,10 @@ extension Fuzzilli_Protobuf_CallMethodWithSpread: SwiftProtobuf.Message, SwiftPr - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -- case 3: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.methodName) -+ case 2: try decoder.decodeRepeatedBoolField(value: &self.spreads) -+ case 3: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5860,11 +5458,8 @@ extension Fuzzilli_Protobuf_CallComputedMethod: SwiftProtobuf.Message, SwiftProt - - 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.isGuarded) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5893,12 +5488,9 @@ extension Fuzzilli_Protobuf_CallComputedMethodWithSpread: SwiftProtobuf.Message, - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.isGuarded) }() -+ case 1: try decoder.decodeRepeatedBoolField(value: &self.spreads) -+ case 2: try decoder.decodeSingularBoolField(value: &self.isGuarded) - default: break - } - } -@@ -5930,11 +5522,8 @@ extension Fuzzilli_Protobuf_UnaryOperation: SwiftProtobuf.Message, SwiftProtobuf - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -5962,11 +5551,8 @@ extension Fuzzilli_Protobuf_BinaryOperation: SwiftProtobuf.Message, SwiftProtobu - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -6013,11 +5599,8 @@ extension Fuzzilli_Protobuf_Update: SwiftProtobuf.Message, SwiftProtobuf._Messag - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -6084,12 +5667,9 @@ extension Fuzzilli_Protobuf_DestructArray: SwiftProtobuf.Message, SwiftProtobuf. - - 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.decodeRepeatedInt32Field(value: &self.indices) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.lastIsRest) }() -+ case 1: try decoder.decodeRepeatedInt32Field(value: &self.indices) -+ case 2: try decoder.decodeSingularBoolField(value: &self.lastIsRest) - default: break - } - } -@@ -6122,12 +5702,9 @@ extension Fuzzilli_Protobuf_DestructArrayAndReassign: SwiftProtobuf.Message, Swi - - 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.decodeRepeatedInt32Field(value: &self.indices) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.lastIsRest) }() -+ case 1: try decoder.decodeRepeatedInt32Field(value: &self.indices) -+ case 2: try decoder.decodeSingularBoolField(value: &self.lastIsRest) - default: break - } - } -@@ -6160,12 +5737,9 @@ extension Fuzzilli_Protobuf_DestructObject: SwiftProtobuf.Message, SwiftProtobuf - - 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.decodeRepeatedStringField(value: &self.properties) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) }() -+ case 1: try decoder.decodeRepeatedStringField(value: &self.properties) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) - default: break - } - } -@@ -6198,12 +5772,9 @@ extension Fuzzilli_Protobuf_DestructObjectAndReassign: SwiftProtobuf.Message, Sw - - 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.decodeRepeatedStringField(value: &self.properties) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) }() -+ case 1: try decoder.decodeRepeatedStringField(value: &self.properties) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) - default: break - } - } -@@ -6235,11 +5806,8 @@ extension Fuzzilli_Protobuf_Compare: SwiftProtobuf.Message, SwiftProtobuf._Messa - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -6267,11 +5835,8 @@ extension Fuzzilli_Protobuf_LoadNamedVariable: SwiftProtobuf.Message, SwiftProto - - 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.variableName) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.variableName) - default: break - } - } -@@ -6299,11 +5864,8 @@ extension Fuzzilli_Protobuf_StoreNamedVariable: SwiftProtobuf.Message, SwiftProt - - 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.variableName) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.variableName) - default: break - } - } -@@ -6331,11 +5893,8 @@ extension Fuzzilli_Protobuf_DefineNamedVariable: SwiftProtobuf.Message, SwiftPro - - 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.variableName) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.variableName) - default: break - } - } -@@ -6364,12 +5923,9 @@ extension Fuzzilli_Protobuf_Eval: SwiftProtobuf.Message, SwiftProtobuf._MessageI - - 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.code) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasOutput_p) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.code) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasOutput_p) - default: break - } - } -@@ -6401,11 +5957,8 @@ extension Fuzzilli_Protobuf_CallSuperConstructor: SwiftProtobuf.Message, SwiftPr - - 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.decodeRepeatedBoolField(value: &self.spreads) }() -+ case 1: try decoder.decodeRepeatedBoolField(value: &self.spreads) - default: break - } - } -@@ -6433,11 +5986,8 @@ extension Fuzzilli_Protobuf_CallSuperMethod: SwiftProtobuf.Message, SwiftProtobu - - 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 1: try decoder.decodeSingularStringField(value: &self.methodName) - default: break - } - } -@@ -6465,11 +6015,8 @@ extension Fuzzilli_Protobuf_GetPrivateProperty: SwiftProtobuf.Message, SwiftProt - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -6497,11 +6044,8 @@ extension Fuzzilli_Protobuf_SetPrivateProperty: SwiftProtobuf.Message, SwiftProt - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -6530,12 +6074,9 @@ extension Fuzzilli_Protobuf_UpdatePrivateProperty: SwiftProtobuf.Message, SwiftP - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -6567,11 +6108,8 @@ extension Fuzzilli_Protobuf_CallPrivateMethod: SwiftProtobuf.Message, SwiftProto - - 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 1: try decoder.decodeSingularStringField(value: &self.methodName) - default: break - } - } -@@ -6599,11 +6137,8 @@ extension Fuzzilli_Protobuf_GetSuperProperty: SwiftProtobuf.Message, SwiftProtob - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -6631,11 +6166,8 @@ extension Fuzzilli_Protobuf_SetSuperProperty: SwiftProtobuf.Message, SwiftProtob - - 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 1: try decoder.decodeSingularStringField(value: &self.propertyName) - default: break - } - } -@@ -6702,12 +6234,9 @@ extension Fuzzilli_Protobuf_UpdateSuperProperty: SwiftProtobuf.Message, SwiftPro - - 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.decodeSingularEnumField(value: &self.op) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.propertyName) -+ case 2: try decoder.decodeSingularEnumField(value: &self.op) - default: break - } - } -@@ -6759,12 +6288,9 @@ extension Fuzzilli_Protobuf_Explore: SwiftProtobuf.Message, SwiftProtobuf._Messa - - 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.id) }() -- case 2: try { try decoder.decodeSingularInt64Field(value: &self.rngSeed) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.id) -+ case 2: try decoder.decodeSingularInt64Field(value: &self.rngSeed) - default: break - } - } -@@ -6796,11 +6322,8 @@ extension Fuzzilli_Protobuf_Probe: SwiftProtobuf.Message, SwiftProtobuf._Message - - 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.id) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.id) - default: break - } - } -@@ -6831,14 +6354,11 @@ extension Fuzzilli_Protobuf_Fixup: SwiftProtobuf.Message, SwiftProtobuf._Message - - 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.id) }() -- case 2: try { try decoder.decodeSingularStringField(value: &self.action) }() -- case 3: try { try decoder.decodeSingularStringField(value: &self.originalOperation) }() -- case 4: try { try decoder.decodeSingularBoolField(value: &self.hasOutput_p) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.id) -+ case 2: try decoder.decodeSingularStringField(value: &self.action) -+ case 3: try decoder.decodeSingularStringField(value: &self.originalOperation) -+ case 4: try decoder.decodeSingularBoolField(value: &self.hasOutput_p) - default: break - } - } -@@ -6916,11 +6436,8 @@ extension Fuzzilli_Protobuf_BeginIf: SwiftProtobuf.Message, SwiftProtobuf._Messa - - 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.inverted) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.inverted) - default: break - } - } -@@ -7062,11 +6579,8 @@ extension Fuzzilli_Protobuf_EndSwitchCase: SwiftProtobuf.Message, SwiftProtobuf. - - 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.fallsThrough) }() -+ case 1: try decoder.decodeSingularBoolField(value: &self.fallsThrough) - default: break - } - } -@@ -7380,12 +6894,9 @@ extension Fuzzilli_Protobuf_BeginForOfLoopWithDestruct: SwiftProtobuf.Message, S - - 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.decodeRepeatedInt32Field(value: &self.indices) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) }() -+ case 1: try decoder.decodeRepeatedInt32Field(value: &self.indices) -+ case 2: try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) - default: break - } - } -@@ -7437,12 +6948,9 @@ extension Fuzzilli_Protobuf_BeginRepeatLoop: SwiftProtobuf.Message, SwiftProtobu - - 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.decodeSingularInt64Field(value: &self.iterations) }() -- case 2: try { try decoder.decodeSingularBoolField(value: &self.exposesLoopCounter) }() -+ case 1: try decoder.decodeSingularInt64Field(value: &self.iterations) -+ case 2: try decoder.decodeSingularBoolField(value: &self.exposesLoopCounter) - default: break - } - } -diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto -index 524e45a..35069b8 100644 ---- a/Sources/Fuzzilli/Protobuf/operations.proto -+++ b/Sources/Fuzzilli/Protobuf/operations.proto -@@ -401,6 +401,9 @@ message EndConstructor { - message Return { - } - -+message DifferentialHash { -+} -+ - message Yield { - } - -diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift -index 1d4af9a..bd3fdc0 100644 ---- a/Sources/Fuzzilli/Protobuf/program.pb.swift -+++ b/Sources/Fuzzilli/Protobuf/program.pb.swift -@@ -7,7 +7,7 @@ - // For information on using the generated types, please see the documentation: - // https://github.com/apple/swift-protobuf/ - --// Copyright 2023 Google LLC -+// Copyright 2024 Google LLC - // - // Licensed under the Apache License, Version 2.0 (the "License"); - // you may not use this file except in compliance with the License. -@@ -44,1432 +44,1438 @@ public struct Fuzzilli_Protobuf_Instruction { - /// The operation is either encoded as an index, referring to the nth operation - /// (so that shared operations are also only present once in the protobuf), or - /// as one of the many concrete Operation messages. -- public var inouts: [UInt32] = [] -+ public var inouts: [UInt32] { -+ get {return _storage._inouts} -+ set {_uniqueStorage()._inouts = newValue} -+ } - -- public var operation: Fuzzilli_Protobuf_Instruction.OneOf_Operation? = nil -+ public var operation: OneOf_Operation? { -+ get {return _storage._operation} -+ set {_uniqueStorage()._operation = newValue} -+ } - - public var opIdx: UInt32 { - get { -- if case .opIdx(let v)? = operation {return v} -+ if case .opIdx(let v)? = _storage._operation {return v} - return 0 - } -- set {operation = .opIdx(newValue)} -+ set {_uniqueStorage()._operation = .opIdx(newValue)} - } - - public var nop: Fuzzilli_Protobuf_Nop { - get { -- if case .nop(let v)? = operation {return v} -+ if case .nop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Nop() - } -- set {operation = .nop(newValue)} -+ set {_uniqueStorage()._operation = .nop(newValue)} - } - - public var loadInteger: Fuzzilli_Protobuf_LoadInteger { - get { -- if case .loadInteger(let v)? = operation {return v} -+ if case .loadInteger(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadInteger() - } -- set {operation = .loadInteger(newValue)} -+ set {_uniqueStorage()._operation = .loadInteger(newValue)} - } - - public var loadBigInt: Fuzzilli_Protobuf_LoadBigInt { - get { -- if case .loadBigInt(let v)? = operation {return v} -+ if case .loadBigInt(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadBigInt() - } -- set {operation = .loadBigInt(newValue)} -+ set {_uniqueStorage()._operation = .loadBigInt(newValue)} - } - - public var loadFloat: Fuzzilli_Protobuf_LoadFloat { - get { -- if case .loadFloat(let v)? = operation {return v} -+ if case .loadFloat(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadFloat() - } -- set {operation = .loadFloat(newValue)} -+ set {_uniqueStorage()._operation = .loadFloat(newValue)} - } - - public var loadString: Fuzzilli_Protobuf_LoadString { - get { -- if case .loadString(let v)? = operation {return v} -+ if case .loadString(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadString() - } -- set {operation = .loadString(newValue)} -+ set {_uniqueStorage()._operation = .loadString(newValue)} - } - - public var loadBoolean: Fuzzilli_Protobuf_LoadBoolean { - get { -- if case .loadBoolean(let v)? = operation {return v} -+ if case .loadBoolean(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadBoolean() - } -- set {operation = .loadBoolean(newValue)} -+ set {_uniqueStorage()._operation = .loadBoolean(newValue)} - } - - public var loadUndefined: Fuzzilli_Protobuf_LoadUndefined { - get { -- if case .loadUndefined(let v)? = operation {return v} -+ if case .loadUndefined(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadUndefined() - } -- set {operation = .loadUndefined(newValue)} -+ set {_uniqueStorage()._operation = .loadUndefined(newValue)} - } - - public var loadNull: Fuzzilli_Protobuf_LoadNull { - get { -- if case .loadNull(let v)? = operation {return v} -+ if case .loadNull(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadNull() - } -- set {operation = .loadNull(newValue)} -+ set {_uniqueStorage()._operation = .loadNull(newValue)} - } - - public var loadThis: Fuzzilli_Protobuf_LoadThis { - get { -- if case .loadThis(let v)? = operation {return v} -+ if case .loadThis(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadThis() - } -- set {operation = .loadThis(newValue)} -+ set {_uniqueStorage()._operation = .loadThis(newValue)} - } - - public var loadArguments: Fuzzilli_Protobuf_LoadArguments { - get { -- if case .loadArguments(let v)? = operation {return v} -+ if case .loadArguments(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadArguments() - } -- set {operation = .loadArguments(newValue)} -+ set {_uniqueStorage()._operation = .loadArguments(newValue)} - } - - public var loadRegExp: Fuzzilli_Protobuf_LoadRegExp { - get { -- if case .loadRegExp(let v)? = operation {return v} -+ if case .loadRegExp(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadRegExp() - } -- set {operation = .loadRegExp(newValue)} -+ set {_uniqueStorage()._operation = .loadRegExp(newValue)} - } - - public var beginObjectLiteral: Fuzzilli_Protobuf_BeginObjectLiteral { - get { -- if case .beginObjectLiteral(let v)? = operation {return v} -+ if case .beginObjectLiteral(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginObjectLiteral() - } -- set {operation = .beginObjectLiteral(newValue)} -+ set {_uniqueStorage()._operation = .beginObjectLiteral(newValue)} - } - - public var objectLiteralAddProperty: Fuzzilli_Protobuf_ObjectLiteralAddProperty { - get { -- if case .objectLiteralAddProperty(let v)? = operation {return v} -+ if case .objectLiteralAddProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ObjectLiteralAddProperty() - } -- set {operation = .objectLiteralAddProperty(newValue)} -+ set {_uniqueStorage()._operation = .objectLiteralAddProperty(newValue)} - } - - public var objectLiteralAddElement: Fuzzilli_Protobuf_ObjectLiteralAddElement { - get { -- if case .objectLiteralAddElement(let v)? = operation {return v} -+ if case .objectLiteralAddElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ObjectLiteralAddElement() - } -- set {operation = .objectLiteralAddElement(newValue)} -+ set {_uniqueStorage()._operation = .objectLiteralAddElement(newValue)} - } - - public var objectLiteralAddComputedProperty: Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty { - get { -- if case .objectLiteralAddComputedProperty(let v)? = operation {return v} -+ if case .objectLiteralAddComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty() - } -- set {operation = .objectLiteralAddComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .objectLiteralAddComputedProperty(newValue)} - } - - public var objectLiteralCopyProperties: Fuzzilli_Protobuf_ObjectLiteralCopyProperties { - get { -- if case .objectLiteralCopyProperties(let v)? = operation {return v} -+ if case .objectLiteralCopyProperties(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ObjectLiteralCopyProperties() - } -- set {operation = .objectLiteralCopyProperties(newValue)} -+ set {_uniqueStorage()._operation = .objectLiteralCopyProperties(newValue)} - } - - public var objectLiteralSetPrototype: Fuzzilli_Protobuf_ObjectLiteralSetPrototype { - get { -- if case .objectLiteralSetPrototype(let v)? = operation {return v} -+ if case .objectLiteralSetPrototype(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ObjectLiteralSetPrototype() - } -- set {operation = .objectLiteralSetPrototype(newValue)} -+ set {_uniqueStorage()._operation = .objectLiteralSetPrototype(newValue)} - } - - public var beginObjectLiteralMethod: Fuzzilli_Protobuf_BeginObjectLiteralMethod { - get { -- if case .beginObjectLiteralMethod(let v)? = operation {return v} -+ if case .beginObjectLiteralMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginObjectLiteralMethod() - } -- set {operation = .beginObjectLiteralMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginObjectLiteralMethod(newValue)} - } - - public var endObjectLiteralMethod: Fuzzilli_Protobuf_EndObjectLiteralMethod { - get { -- if case .endObjectLiteralMethod(let v)? = operation {return v} -+ if case .endObjectLiteralMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndObjectLiteralMethod() - } -- set {operation = .endObjectLiteralMethod(newValue)} -+ set {_uniqueStorage()._operation = .endObjectLiteralMethod(newValue)} - } - - public var beginObjectLiteralComputedMethod: Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod { - get { -- if case .beginObjectLiteralComputedMethod(let v)? = operation {return v} -+ if case .beginObjectLiteralComputedMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod() - } -- set {operation = .beginObjectLiteralComputedMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginObjectLiteralComputedMethod(newValue)} - } - - public var endObjectLiteralComputedMethod: Fuzzilli_Protobuf_EndObjectLiteralComputedMethod { - get { -- if case .endObjectLiteralComputedMethod(let v)? = operation {return v} -+ if case .endObjectLiteralComputedMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndObjectLiteralComputedMethod() - } -- set {operation = .endObjectLiteralComputedMethod(newValue)} -+ set {_uniqueStorage()._operation = .endObjectLiteralComputedMethod(newValue)} - } - - public var beginObjectLiteralGetter: Fuzzilli_Protobuf_BeginObjectLiteralGetter { - get { -- if case .beginObjectLiteralGetter(let v)? = operation {return v} -+ if case .beginObjectLiteralGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginObjectLiteralGetter() - } -- set {operation = .beginObjectLiteralGetter(newValue)} -+ set {_uniqueStorage()._operation = .beginObjectLiteralGetter(newValue)} - } - - public var endObjectLiteralGetter: Fuzzilli_Protobuf_EndObjectLiteralGetter { - get { -- if case .endObjectLiteralGetter(let v)? = operation {return v} -+ if case .endObjectLiteralGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndObjectLiteralGetter() - } -- set {operation = .endObjectLiteralGetter(newValue)} -+ set {_uniqueStorage()._operation = .endObjectLiteralGetter(newValue)} - } - - public var beginObjectLiteralSetter: Fuzzilli_Protobuf_BeginObjectLiteralSetter { - get { -- if case .beginObjectLiteralSetter(let v)? = operation {return v} -+ if case .beginObjectLiteralSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginObjectLiteralSetter() - } -- set {operation = .beginObjectLiteralSetter(newValue)} -+ set {_uniqueStorage()._operation = .beginObjectLiteralSetter(newValue)} - } - - public var endObjectLiteralSetter: Fuzzilli_Protobuf_EndObjectLiteralSetter { - get { -- if case .endObjectLiteralSetter(let v)? = operation {return v} -+ if case .endObjectLiteralSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndObjectLiteralSetter() - } -- set {operation = .endObjectLiteralSetter(newValue)} -+ set {_uniqueStorage()._operation = .endObjectLiteralSetter(newValue)} - } - - public var endObjectLiteral: Fuzzilli_Protobuf_EndObjectLiteral { - get { -- if case .endObjectLiteral(let v)? = operation {return v} -+ if case .endObjectLiteral(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndObjectLiteral() - } -- set {operation = .endObjectLiteral(newValue)} -+ set {_uniqueStorage()._operation = .endObjectLiteral(newValue)} - } - - public var beginClassDefinition: Fuzzilli_Protobuf_BeginClassDefinition { - get { -- if case .beginClassDefinition(let v)? = operation {return v} -+ if case .beginClassDefinition(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassDefinition() - } -- set {operation = .beginClassDefinition(newValue)} -+ set {_uniqueStorage()._operation = .beginClassDefinition(newValue)} - } - - public var beginClassConstructor: Fuzzilli_Protobuf_BeginClassConstructor { - get { -- if case .beginClassConstructor(let v)? = operation {return v} -+ if case .beginClassConstructor(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassConstructor() - } -- set {operation = .beginClassConstructor(newValue)} -+ set {_uniqueStorage()._operation = .beginClassConstructor(newValue)} - } - - public var endClassConstructor: Fuzzilli_Protobuf_EndClassConstructor { - get { -- if case .endClassConstructor(let v)? = operation {return v} -+ if case .endClassConstructor(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassConstructor() - } -- set {operation = .endClassConstructor(newValue)} -+ set {_uniqueStorage()._operation = .endClassConstructor(newValue)} - } - - public var classAddInstanceProperty: Fuzzilli_Protobuf_ClassAddInstanceProperty { - get { -- if case .classAddInstanceProperty(let v)? = operation {return v} -+ if case .classAddInstanceProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceProperty() - } -- set {operation = .classAddInstanceProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddInstanceProperty(newValue)} - } - - public var classAddInstanceElement: Fuzzilli_Protobuf_ClassAddInstanceElement { - get { -- if case .classAddInstanceElement(let v)? = operation {return v} -+ if case .classAddInstanceElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceElement() - } -- set {operation = .classAddInstanceElement(newValue)} -+ set {_uniqueStorage()._operation = .classAddInstanceElement(newValue)} - } - - public var classAddInstanceComputedProperty: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty { - get { -- if case .classAddInstanceComputedProperty(let v)? = operation {return v} -+ if case .classAddInstanceComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceComputedProperty() - } -- set {operation = .classAddInstanceComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddInstanceComputedProperty(newValue)} - } - - public var beginClassInstanceMethod: Fuzzilli_Protobuf_BeginClassInstanceMethod { - get { -- if case .beginClassInstanceMethod(let v)? = operation {return v} -+ if case .beginClassInstanceMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceMethod() - } -- set {operation = .beginClassInstanceMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginClassInstanceMethod(newValue)} - } - - public var endClassInstanceMethod: Fuzzilli_Protobuf_EndClassInstanceMethod { - get { -- if case .endClassInstanceMethod(let v)? = operation {return v} -+ if case .endClassInstanceMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceMethod() - } -- set {operation = .endClassInstanceMethod(newValue)} -+ set {_uniqueStorage()._operation = .endClassInstanceMethod(newValue)} - } - - public var beginClassInstanceGetter: Fuzzilli_Protobuf_BeginClassInstanceGetter { - get { -- if case .beginClassInstanceGetter(let v)? = operation {return v} -+ if case .beginClassInstanceGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceGetter() - } -- set {operation = .beginClassInstanceGetter(newValue)} -+ set {_uniqueStorage()._operation = .beginClassInstanceGetter(newValue)} - } - - public var endClassInstanceGetter: Fuzzilli_Protobuf_EndClassInstanceGetter { - get { -- if case .endClassInstanceGetter(let v)? = operation {return v} -+ if case .endClassInstanceGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceGetter() - } -- set {operation = .endClassInstanceGetter(newValue)} -+ set {_uniqueStorage()._operation = .endClassInstanceGetter(newValue)} - } - - public var beginClassInstanceSetter: Fuzzilli_Protobuf_BeginClassInstanceSetter { - get { -- if case .beginClassInstanceSetter(let v)? = operation {return v} -+ if case .beginClassInstanceSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceSetter() - } -- set {operation = .beginClassInstanceSetter(newValue)} -+ set {_uniqueStorage()._operation = .beginClassInstanceSetter(newValue)} - } - - public var endClassInstanceSetter: Fuzzilli_Protobuf_EndClassInstanceSetter { - get { -- if case .endClassInstanceSetter(let v)? = operation {return v} -+ if case .endClassInstanceSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceSetter() - } -- set {operation = .endClassInstanceSetter(newValue)} -+ set {_uniqueStorage()._operation = .endClassInstanceSetter(newValue)} - } - - public var classAddStaticProperty: Fuzzilli_Protobuf_ClassAddStaticProperty { - get { -- if case .classAddStaticProperty(let v)? = operation {return v} -+ if case .classAddStaticProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticProperty() - } -- set {operation = .classAddStaticProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddStaticProperty(newValue)} - } - - public var classAddStaticElement: Fuzzilli_Protobuf_ClassAddStaticElement { - get { -- if case .classAddStaticElement(let v)? = operation {return v} -+ if case .classAddStaticElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticElement() - } -- set {operation = .classAddStaticElement(newValue)} -+ set {_uniqueStorage()._operation = .classAddStaticElement(newValue)} - } - - public var classAddStaticComputedProperty: Fuzzilli_Protobuf_ClassAddStaticComputedProperty { - get { -- if case .classAddStaticComputedProperty(let v)? = operation {return v} -+ if case .classAddStaticComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticComputedProperty() - } -- set {operation = .classAddStaticComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddStaticComputedProperty(newValue)} - } - - public var beginClassStaticInitializer: Fuzzilli_Protobuf_BeginClassStaticInitializer { - get { -- if case .beginClassStaticInitializer(let v)? = operation {return v} -+ if case .beginClassStaticInitializer(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticInitializer() - } -- set {operation = .beginClassStaticInitializer(newValue)} -+ set {_uniqueStorage()._operation = .beginClassStaticInitializer(newValue)} - } - - public var endClassStaticInitializer: Fuzzilli_Protobuf_EndClassStaticInitializer { - get { -- if case .endClassStaticInitializer(let v)? = operation {return v} -+ if case .endClassStaticInitializer(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassStaticInitializer() - } -- set {operation = .endClassStaticInitializer(newValue)} -+ set {_uniqueStorage()._operation = .endClassStaticInitializer(newValue)} - } - - public var beginClassStaticMethod: Fuzzilli_Protobuf_BeginClassStaticMethod { - get { -- if case .beginClassStaticMethod(let v)? = operation {return v} -+ if case .beginClassStaticMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticMethod() - } -- set {operation = .beginClassStaticMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginClassStaticMethod(newValue)} - } - - public var endClassStaticMethod: Fuzzilli_Protobuf_EndClassStaticMethod { - get { -- if case .endClassStaticMethod(let v)? = operation {return v} -+ if case .endClassStaticMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassStaticMethod() - } -- set {operation = .endClassStaticMethod(newValue)} -+ set {_uniqueStorage()._operation = .endClassStaticMethod(newValue)} - } - - public var beginClassStaticGetter: Fuzzilli_Protobuf_BeginClassStaticGetter { - get { -- if case .beginClassStaticGetter(let v)? = operation {return v} -+ if case .beginClassStaticGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticGetter() - } -- set {operation = .beginClassStaticGetter(newValue)} -+ set {_uniqueStorage()._operation = .beginClassStaticGetter(newValue)} - } - - public var endClassStaticGetter: Fuzzilli_Protobuf_EndClassStaticGetter { - get { -- if case .endClassStaticGetter(let v)? = operation {return v} -+ if case .endClassStaticGetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassStaticGetter() - } -- set {operation = .endClassStaticGetter(newValue)} -+ set {_uniqueStorage()._operation = .endClassStaticGetter(newValue)} - } - - public var beginClassStaticSetter: Fuzzilli_Protobuf_BeginClassStaticSetter { - get { -- if case .beginClassStaticSetter(let v)? = operation {return v} -+ if case .beginClassStaticSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticSetter() - } -- set {operation = .beginClassStaticSetter(newValue)} -+ set {_uniqueStorage()._operation = .beginClassStaticSetter(newValue)} - } - - public var endClassStaticSetter: Fuzzilli_Protobuf_EndClassStaticSetter { - get { -- if case .endClassStaticSetter(let v)? = operation {return v} -+ if case .endClassStaticSetter(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassStaticSetter() - } -- set {operation = .endClassStaticSetter(newValue)} -+ set {_uniqueStorage()._operation = .endClassStaticSetter(newValue)} - } - - public var classAddPrivateInstanceProperty: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty { - get { -- if case .classAddPrivateInstanceProperty(let v)? = operation {return v} -+ if case .classAddPrivateInstanceProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty() - } -- set {operation = .classAddPrivateInstanceProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddPrivateInstanceProperty(newValue)} - } - - public var beginClassPrivateInstanceMethod: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod { - get { -- if case .beginClassPrivateInstanceMethod(let v)? = operation {return v} -+ if case .beginClassPrivateInstanceMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod() - } -- set {operation = .beginClassPrivateInstanceMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginClassPrivateInstanceMethod(newValue)} - } - - public var endClassPrivateInstanceMethod: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod { - get { -- if case .endClassPrivateInstanceMethod(let v)? = operation {return v} -+ if case .endClassPrivateInstanceMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - } -- set {operation = .endClassPrivateInstanceMethod(newValue)} -+ set {_uniqueStorage()._operation = .endClassPrivateInstanceMethod(newValue)} - } - - public var classAddPrivateStaticProperty: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty { - get { -- if case .classAddPrivateStaticProperty(let v)? = operation {return v} -+ if case .classAddPrivateStaticProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateStaticProperty() - } -- set {operation = .classAddPrivateStaticProperty(newValue)} -+ set {_uniqueStorage()._operation = .classAddPrivateStaticProperty(newValue)} - } - - public var beginClassPrivateStaticMethod: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod { - get { -- if case .beginClassPrivateStaticMethod(let v)? = operation {return v} -+ if case .beginClassPrivateStaticMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateStaticMethod() - } -- set {operation = .beginClassPrivateStaticMethod(newValue)} -+ set {_uniqueStorage()._operation = .beginClassPrivateStaticMethod(newValue)} - } - - public var endClassPrivateStaticMethod: Fuzzilli_Protobuf_EndClassPrivateStaticMethod { - get { -- if case .endClassPrivateStaticMethod(let v)? = operation {return v} -+ if case .endClassPrivateStaticMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateStaticMethod() - } -- set {operation = .endClassPrivateStaticMethod(newValue)} -+ set {_uniqueStorage()._operation = .endClassPrivateStaticMethod(newValue)} - } - - public var endClassDefinition: Fuzzilli_Protobuf_EndClassDefinition { - get { -- if case .endClassDefinition(let v)? = operation {return v} -+ if case .endClassDefinition(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndClassDefinition() - } -- set {operation = .endClassDefinition(newValue)} -+ set {_uniqueStorage()._operation = .endClassDefinition(newValue)} - } - - public var createArray: Fuzzilli_Protobuf_CreateArray { - get { -- if case .createArray(let v)? = operation {return v} -+ if case .createArray(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CreateArray() - } -- set {operation = .createArray(newValue)} -+ set {_uniqueStorage()._operation = .createArray(newValue)} - } - - public var createIntArray: Fuzzilli_Protobuf_CreateIntArray { - get { -- if case .createIntArray(let v)? = operation {return v} -+ if case .createIntArray(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CreateIntArray() - } -- set {operation = .createIntArray(newValue)} -+ set {_uniqueStorage()._operation = .createIntArray(newValue)} - } - - public var createFloatArray: Fuzzilli_Protobuf_CreateFloatArray { - get { -- if case .createFloatArray(let v)? = operation {return v} -+ if case .createFloatArray(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CreateFloatArray() - } -- set {operation = .createFloatArray(newValue)} -+ set {_uniqueStorage()._operation = .createFloatArray(newValue)} - } - - public var createArrayWithSpread: Fuzzilli_Protobuf_CreateArrayWithSpread { - get { -- if case .createArrayWithSpread(let v)? = operation {return v} -+ if case .createArrayWithSpread(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CreateArrayWithSpread() - } -- set {operation = .createArrayWithSpread(newValue)} -+ set {_uniqueStorage()._operation = .createArrayWithSpread(newValue)} - } - - public var createTemplateString: Fuzzilli_Protobuf_CreateTemplateString { - get { -- if case .createTemplateString(let v)? = operation {return v} -+ if case .createTemplateString(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CreateTemplateString() - } -- set {operation = .createTemplateString(newValue)} -+ set {_uniqueStorage()._operation = .createTemplateString(newValue)} - } - - public var loadBuiltin: Fuzzilli_Protobuf_LoadBuiltin { - get { -- if case .loadBuiltin(let v)? = operation {return v} -+ if case .loadBuiltin(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadBuiltin() - } -- set {operation = .loadBuiltin(newValue)} -+ set {_uniqueStorage()._operation = .loadBuiltin(newValue)} - } - - public var getProperty: Fuzzilli_Protobuf_GetProperty { - get { -- if case .getProperty(let v)? = operation {return v} -+ if case .getProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetProperty() - } -- set {operation = .getProperty(newValue)} -+ set {_uniqueStorage()._operation = .getProperty(newValue)} - } - - public var setProperty: Fuzzilli_Protobuf_SetProperty { - get { -- if case .setProperty(let v)? = operation {return v} -+ if case .setProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetProperty() - } -- set {operation = .setProperty(newValue)} -+ set {_uniqueStorage()._operation = .setProperty(newValue)} - } - - public var updateProperty: Fuzzilli_Protobuf_UpdateProperty { - get { -- if case .updateProperty(let v)? = operation {return v} -+ if case .updateProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UpdateProperty() - } -- set {operation = .updateProperty(newValue)} -+ set {_uniqueStorage()._operation = .updateProperty(newValue)} - } - - public var deleteProperty: Fuzzilli_Protobuf_DeleteProperty { - get { -- if case .deleteProperty(let v)? = operation {return v} -+ if case .deleteProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DeleteProperty() - } -- set {operation = .deleteProperty(newValue)} -+ set {_uniqueStorage()._operation = .deleteProperty(newValue)} - } - - public var configureProperty: Fuzzilli_Protobuf_ConfigureProperty { - get { -- if case .configureProperty(let v)? = operation {return v} -+ if case .configureProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ConfigureProperty() - } -- set {operation = .configureProperty(newValue)} -+ set {_uniqueStorage()._operation = .configureProperty(newValue)} - } - - public var getElement: Fuzzilli_Protobuf_GetElement { - get { -- if case .getElement(let v)? = operation {return v} -+ if case .getElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetElement() - } -- set {operation = .getElement(newValue)} -+ set {_uniqueStorage()._operation = .getElement(newValue)} - } - - public var setElement: Fuzzilli_Protobuf_SetElement { - get { -- if case .setElement(let v)? = operation {return v} -+ if case .setElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetElement() - } -- set {operation = .setElement(newValue)} -+ set {_uniqueStorage()._operation = .setElement(newValue)} - } - - public var updateElement: Fuzzilli_Protobuf_UpdateElement { - get { -- if case .updateElement(let v)? = operation {return v} -+ if case .updateElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UpdateElement() - } -- set {operation = .updateElement(newValue)} -+ set {_uniqueStorage()._operation = .updateElement(newValue)} - } - - public var deleteElement: Fuzzilli_Protobuf_DeleteElement { - get { -- if case .deleteElement(let v)? = operation {return v} -+ if case .deleteElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DeleteElement() - } -- set {operation = .deleteElement(newValue)} -+ set {_uniqueStorage()._operation = .deleteElement(newValue)} - } - - public var configureElement: Fuzzilli_Protobuf_ConfigureElement { - get { -- if case .configureElement(let v)? = operation {return v} -+ if case .configureElement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ConfigureElement() - } -- set {operation = .configureElement(newValue)} -+ set {_uniqueStorage()._operation = .configureElement(newValue)} - } - - public var getComputedProperty: Fuzzilli_Protobuf_GetComputedProperty { - get { -- if case .getComputedProperty(let v)? = operation {return v} -+ if case .getComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetComputedProperty() - } -- set {operation = .getComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .getComputedProperty(newValue)} - } - - public var setComputedProperty: Fuzzilli_Protobuf_SetComputedProperty { - get { -- if case .setComputedProperty(let v)? = operation {return v} -+ if case .setComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetComputedProperty() - } -- set {operation = .setComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .setComputedProperty(newValue)} - } - - public var updateComputedProperty: Fuzzilli_Protobuf_UpdateComputedProperty { - get { -- if case .updateComputedProperty(let v)? = operation {return v} -+ if case .updateComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UpdateComputedProperty() - } -- set {operation = .updateComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .updateComputedProperty(newValue)} - } - - public var deleteComputedProperty: Fuzzilli_Protobuf_DeleteComputedProperty { - get { -- if case .deleteComputedProperty(let v)? = operation {return v} -+ if case .deleteComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DeleteComputedProperty() - } -- set {operation = .deleteComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .deleteComputedProperty(newValue)} - } - - public var configureComputedProperty: Fuzzilli_Protobuf_ConfigureComputedProperty { - get { -- if case .configureComputedProperty(let v)? = operation {return v} -+ if case .configureComputedProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ConfigureComputedProperty() - } -- set {operation = .configureComputedProperty(newValue)} -+ set {_uniqueStorage()._operation = .configureComputedProperty(newValue)} - } - - public var typeOf: Fuzzilli_Protobuf_TypeOf { - get { -- if case .typeOf(let v)? = operation {return v} -+ if case .typeOf(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_TypeOf() - } -- set {operation = .typeOf(newValue)} -+ set {_uniqueStorage()._operation = .typeOf(newValue)} - } - - public var testInstanceOf: Fuzzilli_Protobuf_TestInstanceOf { - get { -- if case .testInstanceOf(let v)? = operation {return v} -+ if case .testInstanceOf(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_TestInstanceOf() - } -- set {operation = .testInstanceOf(newValue)} -+ set {_uniqueStorage()._operation = .testInstanceOf(newValue)} - } - - public var testIn: Fuzzilli_Protobuf_TestIn { - get { -- if case .testIn(let v)? = operation {return v} -+ if case .testIn(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_TestIn() - } -- set {operation = .testIn(newValue)} -+ set {_uniqueStorage()._operation = .testIn(newValue)} - } - - public var beginPlainFunction: Fuzzilli_Protobuf_BeginPlainFunction { - get { -- if case .beginPlainFunction(let v)? = operation {return v} -+ if case .beginPlainFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginPlainFunction() - } -- set {operation = .beginPlainFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginPlainFunction(newValue)} - } - - public var endPlainFunction: Fuzzilli_Protobuf_EndPlainFunction { - get { -- if case .endPlainFunction(let v)? = operation {return v} -+ if case .endPlainFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndPlainFunction() - } -- set {operation = .endPlainFunction(newValue)} -+ set {_uniqueStorage()._operation = .endPlainFunction(newValue)} - } - - public var beginArrowFunction: Fuzzilli_Protobuf_BeginArrowFunction { - get { -- if case .beginArrowFunction(let v)? = operation {return v} -+ if case .beginArrowFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginArrowFunction() - } -- set {operation = .beginArrowFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginArrowFunction(newValue)} - } - - public var endArrowFunction: Fuzzilli_Protobuf_EndArrowFunction { - get { -- if case .endArrowFunction(let v)? = operation {return v} -+ if case .endArrowFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndArrowFunction() - } -- set {operation = .endArrowFunction(newValue)} -+ set {_uniqueStorage()._operation = .endArrowFunction(newValue)} - } - - public var beginGeneratorFunction: Fuzzilli_Protobuf_BeginGeneratorFunction { - get { -- if case .beginGeneratorFunction(let v)? = operation {return v} -+ if case .beginGeneratorFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginGeneratorFunction() - } -- set {operation = .beginGeneratorFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginGeneratorFunction(newValue)} - } - - public var endGeneratorFunction: Fuzzilli_Protobuf_EndGeneratorFunction { - get { -- if case .endGeneratorFunction(let v)? = operation {return v} -+ if case .endGeneratorFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndGeneratorFunction() - } -- set {operation = .endGeneratorFunction(newValue)} -+ set {_uniqueStorage()._operation = .endGeneratorFunction(newValue)} - } - - public var beginAsyncFunction: Fuzzilli_Protobuf_BeginAsyncFunction { - get { -- if case .beginAsyncFunction(let v)? = operation {return v} -+ if case .beginAsyncFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginAsyncFunction() - } -- set {operation = .beginAsyncFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginAsyncFunction(newValue)} - } - - public var endAsyncFunction: Fuzzilli_Protobuf_EndAsyncFunction { - get { -- if case .endAsyncFunction(let v)? = operation {return v} -+ if case .endAsyncFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndAsyncFunction() - } -- set {operation = .endAsyncFunction(newValue)} -+ set {_uniqueStorage()._operation = .endAsyncFunction(newValue)} - } - - public var beginAsyncArrowFunction: Fuzzilli_Protobuf_BeginAsyncArrowFunction { - get { -- if case .beginAsyncArrowFunction(let v)? = operation {return v} -+ if case .beginAsyncArrowFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginAsyncArrowFunction() - } -- set {operation = .beginAsyncArrowFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginAsyncArrowFunction(newValue)} - } - - public var endAsyncArrowFunction: Fuzzilli_Protobuf_EndAsyncArrowFunction { - get { -- if case .endAsyncArrowFunction(let v)? = operation {return v} -+ if case .endAsyncArrowFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndAsyncArrowFunction() - } -- set {operation = .endAsyncArrowFunction(newValue)} -+ set {_uniqueStorage()._operation = .endAsyncArrowFunction(newValue)} - } - - public var beginAsyncGeneratorFunction: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction { - get { -- if case .beginAsyncGeneratorFunction(let v)? = operation {return v} -+ if case .beginAsyncGeneratorFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginAsyncGeneratorFunction() - } -- set {operation = .beginAsyncGeneratorFunction(newValue)} -+ set {_uniqueStorage()._operation = .beginAsyncGeneratorFunction(newValue)} - } - - public var endAsyncGeneratorFunction: Fuzzilli_Protobuf_EndAsyncGeneratorFunction { - get { -- if case .endAsyncGeneratorFunction(let v)? = operation {return v} -+ if case .endAsyncGeneratorFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndAsyncGeneratorFunction() - } -- set {operation = .endAsyncGeneratorFunction(newValue)} -+ set {_uniqueStorage()._operation = .endAsyncGeneratorFunction(newValue)} - } - - public var beginConstructor: Fuzzilli_Protobuf_BeginConstructor { - get { -- if case .beginConstructor(let v)? = operation {return v} -+ if case .beginConstructor(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginConstructor() - } -- set {operation = .beginConstructor(newValue)} -+ set {_uniqueStorage()._operation = .beginConstructor(newValue)} - } - - public var endConstructor: Fuzzilli_Protobuf_EndConstructor { - get { -- if case .endConstructor(let v)? = operation {return v} -+ if case .endConstructor(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndConstructor() - } -- set {operation = .endConstructor(newValue)} -+ set {_uniqueStorage()._operation = .endConstructor(newValue)} - } - - public var `return`: Fuzzilli_Protobuf_Return { - get { -- if case .return(let v)? = operation {return v} -+ if case .return(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Return() - } -- set {operation = .return(newValue)} -+ set {_uniqueStorage()._operation = .return(newValue)} - } - - public var yield: Fuzzilli_Protobuf_Yield { - get { -- if case .yield(let v)? = operation {return v} -+ if case .yield(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Yield() - } -- set {operation = .yield(newValue)} -+ set {_uniqueStorage()._operation = .yield(newValue)} - } - - public var yieldEach: Fuzzilli_Protobuf_YieldEach { - get { -- if case .yieldEach(let v)? = operation {return v} -+ if case .yieldEach(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_YieldEach() - } -- set {operation = .yieldEach(newValue)} -+ set {_uniqueStorage()._operation = .yieldEach(newValue)} - } - - public var await: Fuzzilli_Protobuf_Await { - get { -- if case .await(let v)? = operation {return v} -+ if case .await(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Await() - } -- set {operation = .await(newValue)} -+ set {_uniqueStorage()._operation = .await(newValue)} - } - - public var callFunction: Fuzzilli_Protobuf_CallFunction { - get { -- if case .callFunction(let v)? = operation {return v} -+ if case .callFunction(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallFunction() - } -- set {operation = .callFunction(newValue)} -+ set {_uniqueStorage()._operation = .callFunction(newValue)} - } - - public var callFunctionWithSpread: Fuzzilli_Protobuf_CallFunctionWithSpread { - get { -- if case .callFunctionWithSpread(let v)? = operation {return v} -+ if case .callFunctionWithSpread(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallFunctionWithSpread() - } -- set {operation = .callFunctionWithSpread(newValue)} -+ set {_uniqueStorage()._operation = .callFunctionWithSpread(newValue)} - } - - public var construct: Fuzzilli_Protobuf_Construct { - get { -- if case .construct(let v)? = operation {return v} -+ if case .construct(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Construct() - } -- set {operation = .construct(newValue)} -+ set {_uniqueStorage()._operation = .construct(newValue)} - } - - public var constructWithSpread: Fuzzilli_Protobuf_ConstructWithSpread { - get { -- if case .constructWithSpread(let v)? = operation {return v} -+ if case .constructWithSpread(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ConstructWithSpread() - } -- set {operation = .constructWithSpread(newValue)} -+ set {_uniqueStorage()._operation = .constructWithSpread(newValue)} - } - - public var callMethod: Fuzzilli_Protobuf_CallMethod { - get { -- if case .callMethod(let v)? = operation {return v} -+ if case .callMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallMethod() - } -- set {operation = .callMethod(newValue)} -+ set {_uniqueStorage()._operation = .callMethod(newValue)} - } - - public var callMethodWithSpread: Fuzzilli_Protobuf_CallMethodWithSpread { - get { -- if case .callMethodWithSpread(let v)? = operation {return v} -+ if case .callMethodWithSpread(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallMethodWithSpread() - } -- set {operation = .callMethodWithSpread(newValue)} -+ set {_uniqueStorage()._operation = .callMethodWithSpread(newValue)} - } - - public var callComputedMethod: Fuzzilli_Protobuf_CallComputedMethod { - get { -- if case .callComputedMethod(let v)? = operation {return v} -+ if case .callComputedMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallComputedMethod() - } -- set {operation = .callComputedMethod(newValue)} -+ set {_uniqueStorage()._operation = .callComputedMethod(newValue)} - } - - public var callComputedMethodWithSpread: Fuzzilli_Protobuf_CallComputedMethodWithSpread { - get { -- if case .callComputedMethodWithSpread(let v)? = operation {return v} -+ if case .callComputedMethodWithSpread(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallComputedMethodWithSpread() - } -- set {operation = .callComputedMethodWithSpread(newValue)} -+ set {_uniqueStorage()._operation = .callComputedMethodWithSpread(newValue)} - } - - public var unaryOperation: Fuzzilli_Protobuf_UnaryOperation { - get { -- if case .unaryOperation(let v)? = operation {return v} -+ if case .unaryOperation(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UnaryOperation() - } -- set {operation = .unaryOperation(newValue)} -+ set {_uniqueStorage()._operation = .unaryOperation(newValue)} - } - - public var binaryOperation: Fuzzilli_Protobuf_BinaryOperation { - get { -- if case .binaryOperation(let v)? = operation {return v} -+ if case .binaryOperation(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BinaryOperation() - } -- set {operation = .binaryOperation(newValue)} -+ set {_uniqueStorage()._operation = .binaryOperation(newValue)} - } - - public var ternaryOperation: Fuzzilli_Protobuf_TernaryOperation { - get { -- if case .ternaryOperation(let v)? = operation {return v} -+ if case .ternaryOperation(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_TernaryOperation() - } -- set {operation = .ternaryOperation(newValue)} -+ set {_uniqueStorage()._operation = .ternaryOperation(newValue)} - } - - public var update: Fuzzilli_Protobuf_Update { - get { -- if case .update(let v)? = operation {return v} -+ if case .update(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Update() - } -- set {operation = .update(newValue)} -+ set {_uniqueStorage()._operation = .update(newValue)} - } - - public var dup: Fuzzilli_Protobuf_Dup { - get { -- if case .dup(let v)? = operation {return v} -+ if case .dup(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Dup() - } -- set {operation = .dup(newValue)} -+ set {_uniqueStorage()._operation = .dup(newValue)} - } - - public var reassign: Fuzzilli_Protobuf_Reassign { - get { -- if case .reassign(let v)? = operation {return v} -+ if case .reassign(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Reassign() - } -- set {operation = .reassign(newValue)} -+ set {_uniqueStorage()._operation = .reassign(newValue)} - } - - public var destructArray: Fuzzilli_Protobuf_DestructArray { - get { -- if case .destructArray(let v)? = operation {return v} -+ if case .destructArray(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DestructArray() - } -- set {operation = .destructArray(newValue)} -+ set {_uniqueStorage()._operation = .destructArray(newValue)} - } - - public var destructArrayAndReassign: Fuzzilli_Protobuf_DestructArrayAndReassign { - get { -- if case .destructArrayAndReassign(let v)? = operation {return v} -+ if case .destructArrayAndReassign(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DestructArrayAndReassign() - } -- set {operation = .destructArrayAndReassign(newValue)} -+ set {_uniqueStorage()._operation = .destructArrayAndReassign(newValue)} - } - - public var destructObject: Fuzzilli_Protobuf_DestructObject { - get { -- if case .destructObject(let v)? = operation {return v} -+ if case .destructObject(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DestructObject() - } -- set {operation = .destructObject(newValue)} -+ set {_uniqueStorage()._operation = .destructObject(newValue)} - } - - public var destructObjectAndReassign: Fuzzilli_Protobuf_DestructObjectAndReassign { - get { -- if case .destructObjectAndReassign(let v)? = operation {return v} -+ if case .destructObjectAndReassign(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DestructObjectAndReassign() - } -- set {operation = .destructObjectAndReassign(newValue)} -+ set {_uniqueStorage()._operation = .destructObjectAndReassign(newValue)} - } - - public var compare: Fuzzilli_Protobuf_Compare { - get { -- if case .compare(let v)? = operation {return v} -+ if case .compare(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Compare() - } -- set {operation = .compare(newValue)} -+ set {_uniqueStorage()._operation = .compare(newValue)} - } - - public var loadNamedVariable: Fuzzilli_Protobuf_LoadNamedVariable { - get { -- if case .loadNamedVariable(let v)? = operation {return v} -+ if case .loadNamedVariable(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadNamedVariable() - } -- set {operation = .loadNamedVariable(newValue)} -+ set {_uniqueStorage()._operation = .loadNamedVariable(newValue)} - } - - public var storeNamedVariable: Fuzzilli_Protobuf_StoreNamedVariable { - get { -- if case .storeNamedVariable(let v)? = operation {return v} -+ if case .storeNamedVariable(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_StoreNamedVariable() - } -- set {operation = .storeNamedVariable(newValue)} -+ set {_uniqueStorage()._operation = .storeNamedVariable(newValue)} - } - - public var defineNamedVariable: Fuzzilli_Protobuf_DefineNamedVariable { - get { -- if case .defineNamedVariable(let v)? = operation {return v} -+ if case .defineNamedVariable(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_DefineNamedVariable() - } -- set {operation = .defineNamedVariable(newValue)} -+ set {_uniqueStorage()._operation = .defineNamedVariable(newValue)} - } - - public var eval: Fuzzilli_Protobuf_Eval { - get { -- if case .eval(let v)? = operation {return v} -+ if case .eval(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Eval() - } -- set {operation = .eval(newValue)} -+ set {_uniqueStorage()._operation = .eval(newValue)} - } - - public var beginWith: Fuzzilli_Protobuf_BeginWith { - get { -- if case .beginWith(let v)? = operation {return v} -+ if case .beginWith(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginWith() - } -- set {operation = .beginWith(newValue)} -+ set {_uniqueStorage()._operation = .beginWith(newValue)} - } - - public var endWith: Fuzzilli_Protobuf_EndWith { - get { -- if case .endWith(let v)? = operation {return v} -+ if case .endWith(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndWith() - } -- set {operation = .endWith(newValue)} -+ set {_uniqueStorage()._operation = .endWith(newValue)} - } - - public var callSuperConstructor: Fuzzilli_Protobuf_CallSuperConstructor { - get { -- if case .callSuperConstructor(let v)? = operation {return v} -+ if case .callSuperConstructor(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallSuperConstructor() - } -- set {operation = .callSuperConstructor(newValue)} -+ set {_uniqueStorage()._operation = .callSuperConstructor(newValue)} - } - - public var callSuperMethod: Fuzzilli_Protobuf_CallSuperMethod { - get { -- if case .callSuperMethod(let v)? = operation {return v} -+ if case .callSuperMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallSuperMethod() - } -- set {operation = .callSuperMethod(newValue)} -+ set {_uniqueStorage()._operation = .callSuperMethod(newValue)} - } - - public var getPrivateProperty: Fuzzilli_Protobuf_GetPrivateProperty { - get { -- if case .getPrivateProperty(let v)? = operation {return v} -+ if case .getPrivateProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetPrivateProperty() - } -- set {operation = .getPrivateProperty(newValue)} -+ set {_uniqueStorage()._operation = .getPrivateProperty(newValue)} - } - - public var setPrivateProperty: Fuzzilli_Protobuf_SetPrivateProperty { - get { -- if case .setPrivateProperty(let v)? = operation {return v} -+ if case .setPrivateProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetPrivateProperty() - } -- set {operation = .setPrivateProperty(newValue)} -+ set {_uniqueStorage()._operation = .setPrivateProperty(newValue)} - } - - public var updatePrivateProperty: Fuzzilli_Protobuf_UpdatePrivateProperty { - get { -- if case .updatePrivateProperty(let v)? = operation {return v} -+ if case .updatePrivateProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UpdatePrivateProperty() - } -- set {operation = .updatePrivateProperty(newValue)} -+ set {_uniqueStorage()._operation = .updatePrivateProperty(newValue)} - } - - public var callPrivateMethod: Fuzzilli_Protobuf_CallPrivateMethod { - get { -- if case .callPrivateMethod(let v)? = operation {return v} -+ if case .callPrivateMethod(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_CallPrivateMethod() - } -- set {operation = .callPrivateMethod(newValue)} -+ set {_uniqueStorage()._operation = .callPrivateMethod(newValue)} - } - - public var getSuperProperty: Fuzzilli_Protobuf_GetSuperProperty { - get { -- if case .getSuperProperty(let v)? = operation {return v} -+ if case .getSuperProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetSuperProperty() - } -- set {operation = .getSuperProperty(newValue)} -+ set {_uniqueStorage()._operation = .getSuperProperty(newValue)} - } - - public var setSuperProperty: Fuzzilli_Protobuf_SetSuperProperty { - get { -- if case .setSuperProperty(let v)? = operation {return v} -+ if case .setSuperProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetSuperProperty() - } -- set {operation = .setSuperProperty(newValue)} -+ set {_uniqueStorage()._operation = .setSuperProperty(newValue)} - } - - public var getComputedSuperProperty: Fuzzilli_Protobuf_GetComputedSuperProperty { - get { -- if case .getComputedSuperProperty(let v)? = operation {return v} -+ if case .getComputedSuperProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_GetComputedSuperProperty() - } -- set {operation = .getComputedSuperProperty(newValue)} -+ set {_uniqueStorage()._operation = .getComputedSuperProperty(newValue)} - } - - public var setComputedSuperProperty: Fuzzilli_Protobuf_SetComputedSuperProperty { - get { -- if case .setComputedSuperProperty(let v)? = operation {return v} -+ if case .setComputedSuperProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SetComputedSuperProperty() - } -- set {operation = .setComputedSuperProperty(newValue)} -+ set {_uniqueStorage()._operation = .setComputedSuperProperty(newValue)} - } - - public var updateSuperProperty: Fuzzilli_Protobuf_UpdateSuperProperty { - get { -- if case .updateSuperProperty(let v)? = operation {return v} -+ if case .updateSuperProperty(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_UpdateSuperProperty() - } -- set {operation = .updateSuperProperty(newValue)} -+ set {_uniqueStorage()._operation = .updateSuperProperty(newValue)} - } - - public var beginIf: Fuzzilli_Protobuf_BeginIf { - get { -- if case .beginIf(let v)? = operation {return v} -+ if case .beginIf(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginIf() - } -- set {operation = .beginIf(newValue)} -+ set {_uniqueStorage()._operation = .beginIf(newValue)} - } - - public var beginElse: Fuzzilli_Protobuf_BeginElse { - get { -- if case .beginElse(let v)? = operation {return v} -+ if case .beginElse(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginElse() - } -- set {operation = .beginElse(newValue)} -+ set {_uniqueStorage()._operation = .beginElse(newValue)} - } - - public var endIf: Fuzzilli_Protobuf_EndIf { - get { -- if case .endIf(let v)? = operation {return v} -+ if case .endIf(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndIf() - } -- set {operation = .endIf(newValue)} -+ set {_uniqueStorage()._operation = .endIf(newValue)} - } - - public var beginWhileLoopHeader: Fuzzilli_Protobuf_BeginWhileLoopHeader { - get { -- if case .beginWhileLoopHeader(let v)? = operation {return v} -+ if case .beginWhileLoopHeader(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginWhileLoopHeader() - } -- set {operation = .beginWhileLoopHeader(newValue)} -+ set {_uniqueStorage()._operation = .beginWhileLoopHeader(newValue)} - } - - public var beginWhileLoopBody: Fuzzilli_Protobuf_BeginWhileLoopBody { - get { -- if case .beginWhileLoopBody(let v)? = operation {return v} -+ if case .beginWhileLoopBody(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginWhileLoopBody() - } -- set {operation = .beginWhileLoopBody(newValue)} -+ set {_uniqueStorage()._operation = .beginWhileLoopBody(newValue)} - } - - public var endWhileLoop: Fuzzilli_Protobuf_EndWhileLoop { - get { -- if case .endWhileLoop(let v)? = operation {return v} -+ if case .endWhileLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndWhileLoop() - } -- set {operation = .endWhileLoop(newValue)} -+ set {_uniqueStorage()._operation = .endWhileLoop(newValue)} - } - - public var beginDoWhileLoopBody: Fuzzilli_Protobuf_BeginDoWhileLoopBody { - get { -- if case .beginDoWhileLoopBody(let v)? = operation {return v} -+ if case .beginDoWhileLoopBody(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginDoWhileLoopBody() - } -- set {operation = .beginDoWhileLoopBody(newValue)} -+ set {_uniqueStorage()._operation = .beginDoWhileLoopBody(newValue)} - } - - public var beginDoWhileLoopHeader: Fuzzilli_Protobuf_BeginDoWhileLoopHeader { - get { -- if case .beginDoWhileLoopHeader(let v)? = operation {return v} -+ if case .beginDoWhileLoopHeader(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginDoWhileLoopHeader() - } -- set {operation = .beginDoWhileLoopHeader(newValue)} -+ set {_uniqueStorage()._operation = .beginDoWhileLoopHeader(newValue)} - } - - public var endDoWhileLoop: Fuzzilli_Protobuf_EndDoWhileLoop { - get { -- if case .endDoWhileLoop(let v)? = operation {return v} -+ if case .endDoWhileLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndDoWhileLoop() - } -- set {operation = .endDoWhileLoop(newValue)} -+ set {_uniqueStorage()._operation = .endDoWhileLoop(newValue)} - } - - public var beginForLoopInitializer: Fuzzilli_Protobuf_BeginForLoopInitializer { - get { -- if case .beginForLoopInitializer(let v)? = operation {return v} -+ if case .beginForLoopInitializer(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForLoopInitializer() - } -- set {operation = .beginForLoopInitializer(newValue)} -+ set {_uniqueStorage()._operation = .beginForLoopInitializer(newValue)} - } - - public var beginForLoopCondition: Fuzzilli_Protobuf_BeginForLoopCondition { - get { -- if case .beginForLoopCondition(let v)? = operation {return v} -+ if case .beginForLoopCondition(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForLoopCondition() - } -- set {operation = .beginForLoopCondition(newValue)} -+ set {_uniqueStorage()._operation = .beginForLoopCondition(newValue)} - } - - public var beginForLoopAfterthought: Fuzzilli_Protobuf_BeginForLoopAfterthought { - get { -- if case .beginForLoopAfterthought(let v)? = operation {return v} -+ if case .beginForLoopAfterthought(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForLoopAfterthought() - } -- set {operation = .beginForLoopAfterthought(newValue)} -+ set {_uniqueStorage()._operation = .beginForLoopAfterthought(newValue)} - } - - public var beginForLoopBody: Fuzzilli_Protobuf_BeginForLoopBody { - get { -- if case .beginForLoopBody(let v)? = operation {return v} -+ if case .beginForLoopBody(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForLoopBody() - } -- set {operation = .beginForLoopBody(newValue)} -+ set {_uniqueStorage()._operation = .beginForLoopBody(newValue)} - } - - public var endForLoop: Fuzzilli_Protobuf_EndForLoop { - get { -- if case .endForLoop(let v)? = operation {return v} -+ if case .endForLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndForLoop() - } -- set {operation = .endForLoop(newValue)} -+ set {_uniqueStorage()._operation = .endForLoop(newValue)} - } - - public var beginForInLoop: Fuzzilli_Protobuf_BeginForInLoop { - get { -- if case .beginForInLoop(let v)? = operation {return v} -+ if case .beginForInLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForInLoop() - } -- set {operation = .beginForInLoop(newValue)} -+ set {_uniqueStorage()._operation = .beginForInLoop(newValue)} - } - - public var endForInLoop: Fuzzilli_Protobuf_EndForInLoop { - get { -- if case .endForInLoop(let v)? = operation {return v} -+ if case .endForInLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndForInLoop() - } -- set {operation = .endForInLoop(newValue)} -+ set {_uniqueStorage()._operation = .endForInLoop(newValue)} - } - - public var beginForOfLoop: Fuzzilli_Protobuf_BeginForOfLoop { - get { -- if case .beginForOfLoop(let v)? = operation {return v} -+ if case .beginForOfLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForOfLoop() - } -- set {operation = .beginForOfLoop(newValue)} -+ set {_uniqueStorage()._operation = .beginForOfLoop(newValue)} - } - - public var beginForOfLoopWithDestruct: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct { - get { -- if case .beginForOfLoopWithDestruct(let v)? = operation {return v} -+ if case .beginForOfLoopWithDestruct(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginForOfLoopWithDestruct() - } -- set {operation = .beginForOfLoopWithDestruct(newValue)} -+ set {_uniqueStorage()._operation = .beginForOfLoopWithDestruct(newValue)} - } - - public var endForOfLoop: Fuzzilli_Protobuf_EndForOfLoop { - get { -- if case .endForOfLoop(let v)? = operation {return v} -+ if case .endForOfLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndForOfLoop() - } -- set {operation = .endForOfLoop(newValue)} -+ set {_uniqueStorage()._operation = .endForOfLoop(newValue)} - } - - public var beginRepeatLoop: Fuzzilli_Protobuf_BeginRepeatLoop { - get { -- if case .beginRepeatLoop(let v)? = operation {return v} -+ if case .beginRepeatLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginRepeatLoop() - } -- set {operation = .beginRepeatLoop(newValue)} -+ set {_uniqueStorage()._operation = .beginRepeatLoop(newValue)} - } - - public var endRepeatLoop: Fuzzilli_Protobuf_EndRepeatLoop { - get { -- if case .endRepeatLoop(let v)? = operation {return v} -+ if case .endRepeatLoop(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndRepeatLoop() - } -- set {operation = .endRepeatLoop(newValue)} -+ set {_uniqueStorage()._operation = .endRepeatLoop(newValue)} - } - - public var loopBreak: Fuzzilli_Protobuf_LoopBreak { - get { -- if case .loopBreak(let v)? = operation {return v} -+ if case .loopBreak(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoopBreak() - } -- set {operation = .loopBreak(newValue)} -+ set {_uniqueStorage()._operation = .loopBreak(newValue)} - } - - public var loopContinue: Fuzzilli_Protobuf_LoopContinue { - get { -- if case .loopContinue(let v)? = operation {return v} -+ if case .loopContinue(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoopContinue() - } -- set {operation = .loopContinue(newValue)} -+ set {_uniqueStorage()._operation = .loopContinue(newValue)} - } - - public var beginTry: Fuzzilli_Protobuf_BeginTry { - get { -- if case .beginTry(let v)? = operation {return v} -+ if case .beginTry(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginTry() - } -- set {operation = .beginTry(newValue)} -+ set {_uniqueStorage()._operation = .beginTry(newValue)} - } - - public var beginCatch: Fuzzilli_Protobuf_BeginCatch { - get { -- if case .beginCatch(let v)? = operation {return v} -+ if case .beginCatch(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginCatch() - } -- set {operation = .beginCatch(newValue)} -+ set {_uniqueStorage()._operation = .beginCatch(newValue)} - } - - public var beginFinally: Fuzzilli_Protobuf_BeginFinally { - get { -- if case .beginFinally(let v)? = operation {return v} -+ if case .beginFinally(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginFinally() - } -- set {operation = .beginFinally(newValue)} -+ set {_uniqueStorage()._operation = .beginFinally(newValue)} - } - - public var endTryCatchFinally: Fuzzilli_Protobuf_EndTryCatchFinally { - get { -- if case .endTryCatchFinally(let v)? = operation {return v} -+ if case .endTryCatchFinally(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndTryCatchFinally() - } -- set {operation = .endTryCatchFinally(newValue)} -+ set {_uniqueStorage()._operation = .endTryCatchFinally(newValue)} - } - - public var throwException: Fuzzilli_Protobuf_ThrowException { - get { -- if case .throwException(let v)? = operation {return v} -+ if case .throwException(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_ThrowException() - } -- set {operation = .throwException(newValue)} -+ set {_uniqueStorage()._operation = .throwException(newValue)} - } - - public var beginCodeString: Fuzzilli_Protobuf_BeginCodeString { - get { -- if case .beginCodeString(let v)? = operation {return v} -+ if case .beginCodeString(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginCodeString() - } -- set {operation = .beginCodeString(newValue)} -+ set {_uniqueStorage()._operation = .beginCodeString(newValue)} - } - - public var endCodeString: Fuzzilli_Protobuf_EndCodeString { - get { -- if case .endCodeString(let v)? = operation {return v} -+ if case .endCodeString(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndCodeString() - } -- set {operation = .endCodeString(newValue)} -+ set {_uniqueStorage()._operation = .endCodeString(newValue)} - } - - public var beginBlockStatement: Fuzzilli_Protobuf_BeginBlockStatement { - get { -- if case .beginBlockStatement(let v)? = operation {return v} -+ if case .beginBlockStatement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginBlockStatement() - } -- set {operation = .beginBlockStatement(newValue)} -+ set {_uniqueStorage()._operation = .beginBlockStatement(newValue)} - } - - public var endBlockStatement: Fuzzilli_Protobuf_EndBlockStatement { - get { -- if case .endBlockStatement(let v)? = operation {return v} -+ if case .endBlockStatement(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndBlockStatement() - } -- set {operation = .endBlockStatement(newValue)} -+ set {_uniqueStorage()._operation = .endBlockStatement(newValue)} - } - - public var beginSwitch: Fuzzilli_Protobuf_BeginSwitch { - get { -- if case .beginSwitch(let v)? = operation {return v} -+ if case .beginSwitch(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginSwitch() - } -- set {operation = .beginSwitch(newValue)} -+ set {_uniqueStorage()._operation = .beginSwitch(newValue)} - } - - public var beginSwitchCase: Fuzzilli_Protobuf_BeginSwitchCase { - get { -- if case .beginSwitchCase(let v)? = operation {return v} -+ if case .beginSwitchCase(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginSwitchCase() - } -- set {operation = .beginSwitchCase(newValue)} -+ set {_uniqueStorage()._operation = .beginSwitchCase(newValue)} - } - - public var beginSwitchDefaultCase: Fuzzilli_Protobuf_BeginSwitchDefaultCase { - get { -- if case .beginSwitchDefaultCase(let v)? = operation {return v} -+ if case .beginSwitchDefaultCase(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_BeginSwitchDefaultCase() - } -- set {operation = .beginSwitchDefaultCase(newValue)} -+ set {_uniqueStorage()._operation = .beginSwitchDefaultCase(newValue)} - } - - public var endSwitchCase: Fuzzilli_Protobuf_EndSwitchCase { - get { -- if case .endSwitchCase(let v)? = operation {return v} -+ if case .endSwitchCase(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndSwitchCase() - } -- set {operation = .endSwitchCase(newValue)} -+ set {_uniqueStorage()._operation = .endSwitchCase(newValue)} - } - - public var endSwitch: Fuzzilli_Protobuf_EndSwitch { - get { -- if case .endSwitch(let v)? = operation {return v} -+ if case .endSwitch(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_EndSwitch() - } -- set {operation = .endSwitch(newValue)} -+ set {_uniqueStorage()._operation = .endSwitch(newValue)} - } - - public var switchBreak: Fuzzilli_Protobuf_SwitchBreak { - get { -- if case .switchBreak(let v)? = operation {return v} -+ if case .switchBreak(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_SwitchBreak() - } -- set {operation = .switchBreak(newValue)} -+ set {_uniqueStorage()._operation = .switchBreak(newValue)} - } - - public var loadNewTarget: Fuzzilli_Protobuf_LoadNewTarget { - get { -- if case .loadNewTarget(let v)? = operation {return v} -+ if case .loadNewTarget(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_LoadNewTarget() - } -- set {operation = .loadNewTarget(newValue)} -+ set {_uniqueStorage()._operation = .loadNewTarget(newValue)} - } - - public var print: Fuzzilli_Protobuf_Print { - get { -- if case .print(let v)? = operation {return v} -+ if case .print(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Print() - } -- set {operation = .print(newValue)} -+ set {_uniqueStorage()._operation = .print(newValue)} - } - - public var explore: Fuzzilli_Protobuf_Explore { - get { -- if case .explore(let v)? = operation {return v} -+ if case .explore(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Explore() - } -- set {operation = .explore(newValue)} -+ set {_uniqueStorage()._operation = .explore(newValue)} - } - - public var probe: Fuzzilli_Protobuf_Probe { - get { -- if case .probe(let v)? = operation {return v} -+ if case .probe(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Probe() - } -- set {operation = .probe(newValue)} -+ set {_uniqueStorage()._operation = .probe(newValue)} - } - - public var fixup: Fuzzilli_Protobuf_Fixup { - get { -- if case .fixup(let v)? = operation {return v} -+ if case .fixup(let v)? = _storage._operation {return v} - return Fuzzilli_Protobuf_Fixup() - } -- set {operation = .fixup(newValue)} -+ set {_uniqueStorage()._operation = .fixup(newValue)} - } - - public var unknownFields = SwiftProtobuf.UnknownStorage() -@@ -1656,722 +1662,185 @@ public struct Fuzzilli_Protobuf_Instruction { - - #if !swift(>=4.1) - public static func ==(lhs: Fuzzilli_Protobuf_Instruction.OneOf_Operation, rhs: Fuzzilli_Protobuf_Instruction.OneOf_Operation) -> Bool { -- // 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 (lhs, rhs) { -- case (.opIdx, .opIdx): return { -- guard case .opIdx(let l) = lhs, case .opIdx(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.nop, .nop): return { -- guard case .nop(let l) = lhs, case .nop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadInteger, .loadInteger): return { -- guard case .loadInteger(let l) = lhs, case .loadInteger(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadBigInt, .loadBigInt): return { -- guard case .loadBigInt(let l) = lhs, case .loadBigInt(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadFloat, .loadFloat): return { -- guard case .loadFloat(let l) = lhs, case .loadFloat(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadString, .loadString): return { -- guard case .loadString(let l) = lhs, case .loadString(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadBoolean, .loadBoolean): return { -- guard case .loadBoolean(let l) = lhs, case .loadBoolean(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadUndefined, .loadUndefined): return { -- guard case .loadUndefined(let l) = lhs, case .loadUndefined(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadNull, .loadNull): return { -- guard case .loadNull(let l) = lhs, case .loadNull(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadThis, .loadThis): return { -- guard case .loadThis(let l) = lhs, case .loadThis(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadArguments, .loadArguments): return { -- guard case .loadArguments(let l) = lhs, case .loadArguments(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadRegExp, .loadRegExp): return { -- guard case .loadRegExp(let l) = lhs, case .loadRegExp(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginObjectLiteral, .beginObjectLiteral): return { -- guard case .beginObjectLiteral(let l) = lhs, case .beginObjectLiteral(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.objectLiteralAddProperty, .objectLiteralAddProperty): return { -- guard case .objectLiteralAddProperty(let l) = lhs, case .objectLiteralAddProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.objectLiteralAddElement, .objectLiteralAddElement): return { -- guard case .objectLiteralAddElement(let l) = lhs, case .objectLiteralAddElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.objectLiteralAddComputedProperty, .objectLiteralAddComputedProperty): return { -- guard case .objectLiteralAddComputedProperty(let l) = lhs, case .objectLiteralAddComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.objectLiteralCopyProperties, .objectLiteralCopyProperties): return { -- guard case .objectLiteralCopyProperties(let l) = lhs, case .objectLiteralCopyProperties(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.objectLiteralSetPrototype, .objectLiteralSetPrototype): return { -- guard case .objectLiteralSetPrototype(let l) = lhs, case .objectLiteralSetPrototype(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginObjectLiteralMethod, .beginObjectLiteralMethod): return { -- guard case .beginObjectLiteralMethod(let l) = lhs, case .beginObjectLiteralMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endObjectLiteralMethod, .endObjectLiteralMethod): return { -- guard case .endObjectLiteralMethod(let l) = lhs, case .endObjectLiteralMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginObjectLiteralComputedMethod, .beginObjectLiteralComputedMethod): return { -- guard case .beginObjectLiteralComputedMethod(let l) = lhs, case .beginObjectLiteralComputedMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endObjectLiteralComputedMethod, .endObjectLiteralComputedMethod): return { -- guard case .endObjectLiteralComputedMethod(let l) = lhs, case .endObjectLiteralComputedMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginObjectLiteralGetter, .beginObjectLiteralGetter): return { -- guard case .beginObjectLiteralGetter(let l) = lhs, case .beginObjectLiteralGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endObjectLiteralGetter, .endObjectLiteralGetter): return { -- guard case .endObjectLiteralGetter(let l) = lhs, case .endObjectLiteralGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginObjectLiteralSetter, .beginObjectLiteralSetter): return { -- guard case .beginObjectLiteralSetter(let l) = lhs, case .beginObjectLiteralSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endObjectLiteralSetter, .endObjectLiteralSetter): return { -- guard case .endObjectLiteralSetter(let l) = lhs, case .endObjectLiteralSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endObjectLiteral, .endObjectLiteral): return { -- guard case .endObjectLiteral(let l) = lhs, case .endObjectLiteral(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassDefinition, .beginClassDefinition): return { -- guard case .beginClassDefinition(let l) = lhs, case .beginClassDefinition(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassConstructor, .beginClassConstructor): return { -- guard case .beginClassConstructor(let l) = lhs, case .beginClassConstructor(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassConstructor, .endClassConstructor): return { -- guard case .endClassConstructor(let l) = lhs, case .endClassConstructor(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddInstanceProperty, .classAddInstanceProperty): return { -- guard case .classAddInstanceProperty(let l) = lhs, case .classAddInstanceProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddInstanceElement, .classAddInstanceElement): return { -- guard case .classAddInstanceElement(let l) = lhs, case .classAddInstanceElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddInstanceComputedProperty, .classAddInstanceComputedProperty): return { -- guard case .classAddInstanceComputedProperty(let l) = lhs, case .classAddInstanceComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassInstanceMethod, .beginClassInstanceMethod): return { -- guard case .beginClassInstanceMethod(let l) = lhs, case .beginClassInstanceMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassInstanceMethod, .endClassInstanceMethod): return { -- guard case .endClassInstanceMethod(let l) = lhs, case .endClassInstanceMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassInstanceGetter, .beginClassInstanceGetter): return { -- guard case .beginClassInstanceGetter(let l) = lhs, case .beginClassInstanceGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassInstanceGetter, .endClassInstanceGetter): return { -- guard case .endClassInstanceGetter(let l) = lhs, case .endClassInstanceGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassInstanceSetter, .beginClassInstanceSetter): return { -- guard case .beginClassInstanceSetter(let l) = lhs, case .beginClassInstanceSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassInstanceSetter, .endClassInstanceSetter): return { -- guard case .endClassInstanceSetter(let l) = lhs, case .endClassInstanceSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddStaticProperty, .classAddStaticProperty): return { -- guard case .classAddStaticProperty(let l) = lhs, case .classAddStaticProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddStaticElement, .classAddStaticElement): return { -- guard case .classAddStaticElement(let l) = lhs, case .classAddStaticElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddStaticComputedProperty, .classAddStaticComputedProperty): return { -- guard case .classAddStaticComputedProperty(let l) = lhs, case .classAddStaticComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassStaticInitializer, .beginClassStaticInitializer): return { -- guard case .beginClassStaticInitializer(let l) = lhs, case .beginClassStaticInitializer(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassStaticInitializer, .endClassStaticInitializer): return { -- guard case .endClassStaticInitializer(let l) = lhs, case .endClassStaticInitializer(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassStaticMethod, .beginClassStaticMethod): return { -- guard case .beginClassStaticMethod(let l) = lhs, case .beginClassStaticMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassStaticMethod, .endClassStaticMethod): return { -- guard case .endClassStaticMethod(let l) = lhs, case .endClassStaticMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassStaticGetter, .beginClassStaticGetter): return { -- guard case .beginClassStaticGetter(let l) = lhs, case .beginClassStaticGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassStaticGetter, .endClassStaticGetter): return { -- guard case .endClassStaticGetter(let l) = lhs, case .endClassStaticGetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassStaticSetter, .beginClassStaticSetter): return { -- guard case .beginClassStaticSetter(let l) = lhs, case .beginClassStaticSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassStaticSetter, .endClassStaticSetter): return { -- guard case .endClassStaticSetter(let l) = lhs, case .endClassStaticSetter(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddPrivateInstanceProperty, .classAddPrivateInstanceProperty): return { -- guard case .classAddPrivateInstanceProperty(let l) = lhs, case .classAddPrivateInstanceProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassPrivateInstanceMethod, .beginClassPrivateInstanceMethod): return { -- guard case .beginClassPrivateInstanceMethod(let l) = lhs, case .beginClassPrivateInstanceMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassPrivateInstanceMethod, .endClassPrivateInstanceMethod): return { -- guard case .endClassPrivateInstanceMethod(let l) = lhs, case .endClassPrivateInstanceMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.classAddPrivateStaticProperty, .classAddPrivateStaticProperty): return { -- guard case .classAddPrivateStaticProperty(let l) = lhs, case .classAddPrivateStaticProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginClassPrivateStaticMethod, .beginClassPrivateStaticMethod): return { -- guard case .beginClassPrivateStaticMethod(let l) = lhs, case .beginClassPrivateStaticMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassPrivateStaticMethod, .endClassPrivateStaticMethod): return { -- guard case .endClassPrivateStaticMethod(let l) = lhs, case .endClassPrivateStaticMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endClassDefinition, .endClassDefinition): return { -- guard case .endClassDefinition(let l) = lhs, case .endClassDefinition(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.createArray, .createArray): return { -- guard case .createArray(let l) = lhs, case .createArray(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.createIntArray, .createIntArray): return { -- guard case .createIntArray(let l) = lhs, case .createIntArray(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.createFloatArray, .createFloatArray): return { -- guard case .createFloatArray(let l) = lhs, case .createFloatArray(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.createArrayWithSpread, .createArrayWithSpread): return { -- guard case .createArrayWithSpread(let l) = lhs, case .createArrayWithSpread(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.createTemplateString, .createTemplateString): return { -- guard case .createTemplateString(let l) = lhs, case .createTemplateString(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadBuiltin, .loadBuiltin): return { -- guard case .loadBuiltin(let l) = lhs, case .loadBuiltin(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getProperty, .getProperty): return { -- guard case .getProperty(let l) = lhs, case .getProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setProperty, .setProperty): return { -- guard case .setProperty(let l) = lhs, case .setProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.updateProperty, .updateProperty): return { -- guard case .updateProperty(let l) = lhs, case .updateProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.deleteProperty, .deleteProperty): return { -- guard case .deleteProperty(let l) = lhs, case .deleteProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.configureProperty, .configureProperty): return { -- guard case .configureProperty(let l) = lhs, case .configureProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getElement, .getElement): return { -- guard case .getElement(let l) = lhs, case .getElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setElement, .setElement): return { -- guard case .setElement(let l) = lhs, case .setElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.updateElement, .updateElement): return { -- guard case .updateElement(let l) = lhs, case .updateElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.deleteElement, .deleteElement): return { -- guard case .deleteElement(let l) = lhs, case .deleteElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.configureElement, .configureElement): return { -- guard case .configureElement(let l) = lhs, case .configureElement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getComputedProperty, .getComputedProperty): return { -- guard case .getComputedProperty(let l) = lhs, case .getComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setComputedProperty, .setComputedProperty): return { -- guard case .setComputedProperty(let l) = lhs, case .setComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.updateComputedProperty, .updateComputedProperty): return { -- guard case .updateComputedProperty(let l) = lhs, case .updateComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.deleteComputedProperty, .deleteComputedProperty): return { -- guard case .deleteComputedProperty(let l) = lhs, case .deleteComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.configureComputedProperty, .configureComputedProperty): return { -- guard case .configureComputedProperty(let l) = lhs, case .configureComputedProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.typeOf, .typeOf): return { -- guard case .typeOf(let l) = lhs, case .typeOf(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.testInstanceOf, .testInstanceOf): return { -- guard case .testInstanceOf(let l) = lhs, case .testInstanceOf(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.testIn, .testIn): return { -- guard case .testIn(let l) = lhs, case .testIn(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginPlainFunction, .beginPlainFunction): return { -- guard case .beginPlainFunction(let l) = lhs, case .beginPlainFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endPlainFunction, .endPlainFunction): return { -- guard case .endPlainFunction(let l) = lhs, case .endPlainFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginArrowFunction, .beginArrowFunction): return { -- guard case .beginArrowFunction(let l) = lhs, case .beginArrowFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endArrowFunction, .endArrowFunction): return { -- guard case .endArrowFunction(let l) = lhs, case .endArrowFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginGeneratorFunction, .beginGeneratorFunction): return { -- guard case .beginGeneratorFunction(let l) = lhs, case .beginGeneratorFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endGeneratorFunction, .endGeneratorFunction): return { -- guard case .endGeneratorFunction(let l) = lhs, case .endGeneratorFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginAsyncFunction, .beginAsyncFunction): return { -- guard case .beginAsyncFunction(let l) = lhs, case .beginAsyncFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endAsyncFunction, .endAsyncFunction): return { -- guard case .endAsyncFunction(let l) = lhs, case .endAsyncFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginAsyncArrowFunction, .beginAsyncArrowFunction): return { -- guard case .beginAsyncArrowFunction(let l) = lhs, case .beginAsyncArrowFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endAsyncArrowFunction, .endAsyncArrowFunction): return { -- guard case .endAsyncArrowFunction(let l) = lhs, case .endAsyncArrowFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginAsyncGeneratorFunction, .beginAsyncGeneratorFunction): return { -- guard case .beginAsyncGeneratorFunction(let l) = lhs, case .beginAsyncGeneratorFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endAsyncGeneratorFunction, .endAsyncGeneratorFunction): return { -- guard case .endAsyncGeneratorFunction(let l) = lhs, case .endAsyncGeneratorFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginConstructor, .beginConstructor): return { -- guard case .beginConstructor(let l) = lhs, case .beginConstructor(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endConstructor, .endConstructor): return { -- guard case .endConstructor(let l) = lhs, case .endConstructor(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.return, .return): return { -- guard case .return(let l) = lhs, case .return(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.yield, .yield): return { -- guard case .yield(let l) = lhs, case .yield(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.yieldEach, .yieldEach): return { -- guard case .yieldEach(let l) = lhs, case .yieldEach(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.await, .await): return { -- guard case .await(let l) = lhs, case .await(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callFunction, .callFunction): return { -- guard case .callFunction(let l) = lhs, case .callFunction(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callFunctionWithSpread, .callFunctionWithSpread): return { -- guard case .callFunctionWithSpread(let l) = lhs, case .callFunctionWithSpread(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.construct, .construct): return { -- guard case .construct(let l) = lhs, case .construct(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.constructWithSpread, .constructWithSpread): return { -- guard case .constructWithSpread(let l) = lhs, case .constructWithSpread(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callMethod, .callMethod): return { -- guard case .callMethod(let l) = lhs, case .callMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callMethodWithSpread, .callMethodWithSpread): return { -- guard case .callMethodWithSpread(let l) = lhs, case .callMethodWithSpread(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callComputedMethod, .callComputedMethod): return { -- guard case .callComputedMethod(let l) = lhs, case .callComputedMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callComputedMethodWithSpread, .callComputedMethodWithSpread): return { -- guard case .callComputedMethodWithSpread(let l) = lhs, case .callComputedMethodWithSpread(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.unaryOperation, .unaryOperation): return { -- guard case .unaryOperation(let l) = lhs, case .unaryOperation(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.binaryOperation, .binaryOperation): return { -- guard case .binaryOperation(let l) = lhs, case .binaryOperation(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.ternaryOperation, .ternaryOperation): return { -- guard case .ternaryOperation(let l) = lhs, case .ternaryOperation(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.update, .update): return { -- guard case .update(let l) = lhs, case .update(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.dup, .dup): return { -- guard case .dup(let l) = lhs, case .dup(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.reassign, .reassign): return { -- guard case .reassign(let l) = lhs, case .reassign(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.destructArray, .destructArray): return { -- guard case .destructArray(let l) = lhs, case .destructArray(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.destructArrayAndReassign, .destructArrayAndReassign): return { -- guard case .destructArrayAndReassign(let l) = lhs, case .destructArrayAndReassign(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.destructObject, .destructObject): return { -- guard case .destructObject(let l) = lhs, case .destructObject(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.destructObjectAndReassign, .destructObjectAndReassign): return { -- guard case .destructObjectAndReassign(let l) = lhs, case .destructObjectAndReassign(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.compare, .compare): return { -- guard case .compare(let l) = lhs, case .compare(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadNamedVariable, .loadNamedVariable): return { -- guard case .loadNamedVariable(let l) = lhs, case .loadNamedVariable(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.storeNamedVariable, .storeNamedVariable): return { -- guard case .storeNamedVariable(let l) = lhs, case .storeNamedVariable(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.defineNamedVariable, .defineNamedVariable): return { -- guard case .defineNamedVariable(let l) = lhs, case .defineNamedVariable(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.eval, .eval): return { -- guard case .eval(let l) = lhs, case .eval(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginWith, .beginWith): return { -- guard case .beginWith(let l) = lhs, case .beginWith(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endWith, .endWith): return { -- guard case .endWith(let l) = lhs, case .endWith(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callSuperConstructor, .callSuperConstructor): return { -- guard case .callSuperConstructor(let l) = lhs, case .callSuperConstructor(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callSuperMethod, .callSuperMethod): return { -- guard case .callSuperMethod(let l) = lhs, case .callSuperMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getPrivateProperty, .getPrivateProperty): return { -- guard case .getPrivateProperty(let l) = lhs, case .getPrivateProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setPrivateProperty, .setPrivateProperty): return { -- guard case .setPrivateProperty(let l) = lhs, case .setPrivateProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.updatePrivateProperty, .updatePrivateProperty): return { -- guard case .updatePrivateProperty(let l) = lhs, case .updatePrivateProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.callPrivateMethod, .callPrivateMethod): return { -- guard case .callPrivateMethod(let l) = lhs, case .callPrivateMethod(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getSuperProperty, .getSuperProperty): return { -- guard case .getSuperProperty(let l) = lhs, case .getSuperProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setSuperProperty, .setSuperProperty): return { -- guard case .setSuperProperty(let l) = lhs, case .setSuperProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.getComputedSuperProperty, .getComputedSuperProperty): return { -- guard case .getComputedSuperProperty(let l) = lhs, case .getComputedSuperProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.setComputedSuperProperty, .setComputedSuperProperty): return { -- guard case .setComputedSuperProperty(let l) = lhs, case .setComputedSuperProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.updateSuperProperty, .updateSuperProperty): return { -- guard case .updateSuperProperty(let l) = lhs, case .updateSuperProperty(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginIf, .beginIf): return { -- guard case .beginIf(let l) = lhs, case .beginIf(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginElse, .beginElse): return { -- guard case .beginElse(let l) = lhs, case .beginElse(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endIf, .endIf): return { -- guard case .endIf(let l) = lhs, case .endIf(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginWhileLoopHeader, .beginWhileLoopHeader): return { -- guard case .beginWhileLoopHeader(let l) = lhs, case .beginWhileLoopHeader(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginWhileLoopBody, .beginWhileLoopBody): return { -- guard case .beginWhileLoopBody(let l) = lhs, case .beginWhileLoopBody(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endWhileLoop, .endWhileLoop): return { -- guard case .endWhileLoop(let l) = lhs, case .endWhileLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginDoWhileLoopBody, .beginDoWhileLoopBody): return { -- guard case .beginDoWhileLoopBody(let l) = lhs, case .beginDoWhileLoopBody(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginDoWhileLoopHeader, .beginDoWhileLoopHeader): return { -- guard case .beginDoWhileLoopHeader(let l) = lhs, case .beginDoWhileLoopHeader(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endDoWhileLoop, .endDoWhileLoop): return { -- guard case .endDoWhileLoop(let l) = lhs, case .endDoWhileLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForLoopInitializer, .beginForLoopInitializer): return { -- guard case .beginForLoopInitializer(let l) = lhs, case .beginForLoopInitializer(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForLoopCondition, .beginForLoopCondition): return { -- guard case .beginForLoopCondition(let l) = lhs, case .beginForLoopCondition(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForLoopAfterthought, .beginForLoopAfterthought): return { -- guard case .beginForLoopAfterthought(let l) = lhs, case .beginForLoopAfterthought(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForLoopBody, .beginForLoopBody): return { -- guard case .beginForLoopBody(let l) = lhs, case .beginForLoopBody(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endForLoop, .endForLoop): return { -- guard case .endForLoop(let l) = lhs, case .endForLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForInLoop, .beginForInLoop): return { -- guard case .beginForInLoop(let l) = lhs, case .beginForInLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endForInLoop, .endForInLoop): return { -- guard case .endForInLoop(let l) = lhs, case .endForInLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForOfLoop, .beginForOfLoop): return { -- guard case .beginForOfLoop(let l) = lhs, case .beginForOfLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginForOfLoopWithDestruct, .beginForOfLoopWithDestruct): return { -- guard case .beginForOfLoopWithDestruct(let l) = lhs, case .beginForOfLoopWithDestruct(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endForOfLoop, .endForOfLoop): return { -- guard case .endForOfLoop(let l) = lhs, case .endForOfLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginRepeatLoop, .beginRepeatLoop): return { -- guard case .beginRepeatLoop(let l) = lhs, case .beginRepeatLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endRepeatLoop, .endRepeatLoop): return { -- guard case .endRepeatLoop(let l) = lhs, case .endRepeatLoop(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loopBreak, .loopBreak): return { -- guard case .loopBreak(let l) = lhs, case .loopBreak(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loopContinue, .loopContinue): return { -- guard case .loopContinue(let l) = lhs, case .loopContinue(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginTry, .beginTry): return { -- guard case .beginTry(let l) = lhs, case .beginTry(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginCatch, .beginCatch): return { -- guard case .beginCatch(let l) = lhs, case .beginCatch(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginFinally, .beginFinally): return { -- guard case .beginFinally(let l) = lhs, case .beginFinally(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endTryCatchFinally, .endTryCatchFinally): return { -- guard case .endTryCatchFinally(let l) = lhs, case .endTryCatchFinally(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.throwException, .throwException): return { -- guard case .throwException(let l) = lhs, case .throwException(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginCodeString, .beginCodeString): return { -- guard case .beginCodeString(let l) = lhs, case .beginCodeString(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endCodeString, .endCodeString): return { -- guard case .endCodeString(let l) = lhs, case .endCodeString(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginBlockStatement, .beginBlockStatement): return { -- guard case .beginBlockStatement(let l) = lhs, case .beginBlockStatement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endBlockStatement, .endBlockStatement): return { -- guard case .endBlockStatement(let l) = lhs, case .endBlockStatement(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginSwitch, .beginSwitch): return { -- guard case .beginSwitch(let l) = lhs, case .beginSwitch(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginSwitchCase, .beginSwitchCase): return { -- guard case .beginSwitchCase(let l) = lhs, case .beginSwitchCase(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.beginSwitchDefaultCase, .beginSwitchDefaultCase): return { -- guard case .beginSwitchDefaultCase(let l) = lhs, case .beginSwitchDefaultCase(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endSwitchCase, .endSwitchCase): return { -- guard case .endSwitchCase(let l) = lhs, case .endSwitchCase(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.endSwitch, .endSwitch): return { -- guard case .endSwitch(let l) = lhs, case .endSwitch(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.switchBreak, .switchBreak): return { -- guard case .switchBreak(let l) = lhs, case .switchBreak(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.loadNewTarget, .loadNewTarget): return { -- guard case .loadNewTarget(let l) = lhs, case .loadNewTarget(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.print, .print): return { -- guard case .print(let l) = lhs, case .print(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.explore, .explore): return { -- guard case .explore(let l) = lhs, case .explore(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.probe, .probe): return { -- guard case .probe(let l) = lhs, case .probe(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -- case (.fixup, .fixup): return { -- guard case .fixup(let l) = lhs, case .fixup(let r) = rhs else { preconditionFailure() } -- return l == r -- }() -+ case (.opIdx(let l), .opIdx(let r)): return l == r -+ case (.nop(let l), .nop(let r)): return l == r -+ case (.loadInteger(let l), .loadInteger(let r)): return l == r -+ case (.loadBigInt(let l), .loadBigInt(let r)): return l == r -+ case (.loadFloat(let l), .loadFloat(let r)): return l == r -+ case (.loadString(let l), .loadString(let r)): return l == r -+ case (.loadBoolean(let l), .loadBoolean(let r)): return l == r -+ case (.loadUndefined(let l), .loadUndefined(let r)): return l == r -+ case (.loadNull(let l), .loadNull(let r)): return l == r -+ case (.loadThis(let l), .loadThis(let r)): return l == r -+ case (.loadArguments(let l), .loadArguments(let r)): return l == r -+ case (.loadRegExp(let l), .loadRegExp(let r)): return l == r -+ case (.beginObjectLiteral(let l), .beginObjectLiteral(let r)): return l == r -+ case (.objectLiteralAddProperty(let l), .objectLiteralAddProperty(let r)): return l == r -+ case (.objectLiteralAddElement(let l), .objectLiteralAddElement(let r)): return l == r -+ case (.objectLiteralAddComputedProperty(let l), .objectLiteralAddComputedProperty(let r)): return l == r -+ case (.objectLiteralCopyProperties(let l), .objectLiteralCopyProperties(let r)): return l == r -+ case (.objectLiteralSetPrototype(let l), .objectLiteralSetPrototype(let r)): return l == r -+ case (.beginObjectLiteralMethod(let l), .beginObjectLiteralMethod(let r)): return l == r -+ case (.endObjectLiteralMethod(let l), .endObjectLiteralMethod(let r)): return l == r -+ case (.beginObjectLiteralComputedMethod(let l), .beginObjectLiteralComputedMethod(let r)): return l == r -+ case (.endObjectLiteralComputedMethod(let l), .endObjectLiteralComputedMethod(let r)): return l == r -+ case (.beginObjectLiteralGetter(let l), .beginObjectLiteralGetter(let r)): return l == r -+ case (.endObjectLiteralGetter(let l), .endObjectLiteralGetter(let r)): return l == r -+ case (.beginObjectLiteralSetter(let l), .beginObjectLiteralSetter(let r)): return l == r -+ case (.endObjectLiteralSetter(let l), .endObjectLiteralSetter(let r)): return l == r -+ case (.endObjectLiteral(let l), .endObjectLiteral(let r)): return l == r -+ case (.beginClassDefinition(let l), .beginClassDefinition(let r)): return l == r -+ case (.beginClassConstructor(let l), .beginClassConstructor(let r)): return l == r -+ case (.endClassConstructor(let l), .endClassConstructor(let r)): return l == r -+ case (.classAddInstanceProperty(let l), .classAddInstanceProperty(let r)): return l == r -+ case (.classAddInstanceElement(let l), .classAddInstanceElement(let r)): return l == r -+ case (.classAddInstanceComputedProperty(let l), .classAddInstanceComputedProperty(let r)): return l == r -+ case (.beginClassInstanceMethod(let l), .beginClassInstanceMethod(let r)): return l == r -+ case (.endClassInstanceMethod(let l), .endClassInstanceMethod(let r)): return l == r -+ case (.beginClassInstanceGetter(let l), .beginClassInstanceGetter(let r)): return l == r -+ case (.endClassInstanceGetter(let l), .endClassInstanceGetter(let r)): return l == r -+ case (.beginClassInstanceSetter(let l), .beginClassInstanceSetter(let r)): return l == r -+ case (.endClassInstanceSetter(let l), .endClassInstanceSetter(let r)): return l == r -+ case (.classAddStaticProperty(let l), .classAddStaticProperty(let r)): return l == r -+ case (.classAddStaticElement(let l), .classAddStaticElement(let r)): return l == r -+ case (.classAddStaticComputedProperty(let l), .classAddStaticComputedProperty(let r)): return l == r -+ case (.beginClassStaticInitializer(let l), .beginClassStaticInitializer(let r)): return l == r -+ case (.endClassStaticInitializer(let l), .endClassStaticInitializer(let r)): return l == r -+ case (.beginClassStaticMethod(let l), .beginClassStaticMethod(let r)): return l == r -+ case (.endClassStaticMethod(let l), .endClassStaticMethod(let r)): return l == r -+ case (.beginClassStaticGetter(let l), .beginClassStaticGetter(let r)): return l == r -+ case (.endClassStaticGetter(let l), .endClassStaticGetter(let r)): return l == r -+ case (.beginClassStaticSetter(let l), .beginClassStaticSetter(let r)): return l == r -+ case (.endClassStaticSetter(let l), .endClassStaticSetter(let r)): return l == r -+ case (.classAddPrivateInstanceProperty(let l), .classAddPrivateInstanceProperty(let r)): return l == r -+ case (.beginClassPrivateInstanceMethod(let l), .beginClassPrivateInstanceMethod(let r)): return l == r -+ case (.endClassPrivateInstanceMethod(let l), .endClassPrivateInstanceMethod(let r)): return l == r -+ case (.classAddPrivateStaticProperty(let l), .classAddPrivateStaticProperty(let r)): return l == r -+ case (.beginClassPrivateStaticMethod(let l), .beginClassPrivateStaticMethod(let r)): return l == r -+ case (.endClassPrivateStaticMethod(let l), .endClassPrivateStaticMethod(let r)): return l == r -+ case (.endClassDefinition(let l), .endClassDefinition(let r)): return l == r -+ case (.createArray(let l), .createArray(let r)): return l == r -+ case (.createIntArray(let l), .createIntArray(let r)): return l == r -+ case (.createFloatArray(let l), .createFloatArray(let r)): return l == r -+ case (.createArrayWithSpread(let l), .createArrayWithSpread(let r)): return l == r -+ case (.createTemplateString(let l), .createTemplateString(let r)): return l == r -+ case (.loadBuiltin(let l), .loadBuiltin(let r)): return l == r -+ case (.getProperty(let l), .getProperty(let r)): return l == r -+ case (.setProperty(let l), .setProperty(let r)): return l == r -+ case (.updateProperty(let l), .updateProperty(let r)): return l == r -+ case (.deleteProperty(let l), .deleteProperty(let r)): return l == r -+ case (.configureProperty(let l), .configureProperty(let r)): return l == r -+ case (.getElement(let l), .getElement(let r)): return l == r -+ case (.setElement(let l), .setElement(let r)): return l == r -+ case (.updateElement(let l), .updateElement(let r)): return l == r -+ case (.deleteElement(let l), .deleteElement(let r)): return l == r -+ case (.configureElement(let l), .configureElement(let r)): return l == r -+ case (.getComputedProperty(let l), .getComputedProperty(let r)): return l == r -+ case (.setComputedProperty(let l), .setComputedProperty(let r)): return l == r -+ case (.updateComputedProperty(let l), .updateComputedProperty(let r)): return l == r -+ case (.deleteComputedProperty(let l), .deleteComputedProperty(let r)): return l == r -+ case (.configureComputedProperty(let l), .configureComputedProperty(let r)): return l == r -+ case (.typeOf(let l), .typeOf(let r)): return l == r -+ case (.testInstanceOf(let l), .testInstanceOf(let r)): return l == r -+ case (.testIn(let l), .testIn(let r)): return l == r -+ case (.beginPlainFunction(let l), .beginPlainFunction(let r)): return l == r -+ case (.endPlainFunction(let l), .endPlainFunction(let r)): return l == r -+ case (.beginArrowFunction(let l), .beginArrowFunction(let r)): return l == r -+ case (.endArrowFunction(let l), .endArrowFunction(let r)): return l == r -+ case (.beginGeneratorFunction(let l), .beginGeneratorFunction(let r)): return l == r -+ case (.endGeneratorFunction(let l), .endGeneratorFunction(let r)): return l == r -+ case (.beginAsyncFunction(let l), .beginAsyncFunction(let r)): return l == r -+ case (.endAsyncFunction(let l), .endAsyncFunction(let r)): return l == r -+ case (.beginAsyncArrowFunction(let l), .beginAsyncArrowFunction(let r)): return l == r -+ case (.endAsyncArrowFunction(let l), .endAsyncArrowFunction(let r)): return l == r -+ case (.beginAsyncGeneratorFunction(let l), .beginAsyncGeneratorFunction(let r)): return l == r -+ case (.endAsyncGeneratorFunction(let l), .endAsyncGeneratorFunction(let r)): return l == r -+ case (.beginConstructor(let l), .beginConstructor(let r)): return l == r -+ case (.endConstructor(let l), .endConstructor(let r)): return l == r -+ case (.return(let l), .return(let r)): return l == r -+ case (.yield(let l), .yield(let r)): return l == r -+ case (.yieldEach(let l), .yieldEach(let r)): return l == r -+ case (.await(let l), .await(let r)): return l == r -+ case (.callFunction(let l), .callFunction(let r)): return l == r -+ case (.callFunctionWithSpread(let l), .callFunctionWithSpread(let r)): return l == r -+ case (.construct(let l), .construct(let r)): return l == r -+ case (.constructWithSpread(let l), .constructWithSpread(let r)): return l == r -+ case (.callMethod(let l), .callMethod(let r)): return l == r -+ case (.callMethodWithSpread(let l), .callMethodWithSpread(let r)): return l == r -+ case (.callComputedMethod(let l), .callComputedMethod(let r)): return l == r -+ case (.callComputedMethodWithSpread(let l), .callComputedMethodWithSpread(let r)): return l == r -+ case (.unaryOperation(let l), .unaryOperation(let r)): return l == r -+ case (.binaryOperation(let l), .binaryOperation(let r)): return l == r -+ case (.ternaryOperation(let l), .ternaryOperation(let r)): return l == r -+ case (.update(let l), .update(let r)): return l == r -+ case (.dup(let l), .dup(let r)): return l == r -+ case (.reassign(let l), .reassign(let r)): return l == r -+ case (.destructArray(let l), .destructArray(let r)): return l == r -+ case (.destructArrayAndReassign(let l), .destructArrayAndReassign(let r)): return l == r -+ case (.destructObject(let l), .destructObject(let r)): return l == r -+ case (.destructObjectAndReassign(let l), .destructObjectAndReassign(let r)): return l == r -+ case (.compare(let l), .compare(let r)): return l == r -+ case (.loadNamedVariable(let l), .loadNamedVariable(let r)): return l == r -+ case (.storeNamedVariable(let l), .storeNamedVariable(let r)): return l == r -+ case (.defineNamedVariable(let l), .defineNamedVariable(let r)): return l == r -+ case (.eval(let l), .eval(let r)): return l == r -+ case (.beginWith(let l), .beginWith(let r)): return l == r -+ case (.endWith(let l), .endWith(let r)): return l == r -+ case (.callSuperConstructor(let l), .callSuperConstructor(let r)): return l == r -+ case (.callSuperMethod(let l), .callSuperMethod(let r)): return l == r -+ case (.getPrivateProperty(let l), .getPrivateProperty(let r)): return l == r -+ case (.setPrivateProperty(let l), .setPrivateProperty(let r)): return l == r -+ case (.updatePrivateProperty(let l), .updatePrivateProperty(let r)): return l == r -+ case (.callPrivateMethod(let l), .callPrivateMethod(let r)): return l == r -+ case (.getSuperProperty(let l), .getSuperProperty(let r)): return l == r -+ case (.setSuperProperty(let l), .setSuperProperty(let r)): return l == r -+ case (.getComputedSuperProperty(let l), .getComputedSuperProperty(let r)): return l == r -+ case (.setComputedSuperProperty(let l), .setComputedSuperProperty(let r)): return l == r -+ case (.updateSuperProperty(let l), .updateSuperProperty(let r)): return l == r -+ case (.beginIf(let l), .beginIf(let r)): return l == r -+ case (.beginElse(let l), .beginElse(let r)): return l == r -+ case (.endIf(let l), .endIf(let r)): return l == r -+ case (.beginWhileLoopHeader(let l), .beginWhileLoopHeader(let r)): return l == r -+ case (.beginWhileLoopBody(let l), .beginWhileLoopBody(let r)): return l == r -+ case (.endWhileLoop(let l), .endWhileLoop(let r)): return l == r -+ case (.beginDoWhileLoopBody(let l), .beginDoWhileLoopBody(let r)): return l == r -+ case (.beginDoWhileLoopHeader(let l), .beginDoWhileLoopHeader(let r)): return l == r -+ case (.endDoWhileLoop(let l), .endDoWhileLoop(let r)): return l == r -+ case (.beginForLoopInitializer(let l), .beginForLoopInitializer(let r)): return l == r -+ case (.beginForLoopCondition(let l), .beginForLoopCondition(let r)): return l == r -+ case (.beginForLoopAfterthought(let l), .beginForLoopAfterthought(let r)): return l == r -+ case (.beginForLoopBody(let l), .beginForLoopBody(let r)): return l == r -+ case (.endForLoop(let l), .endForLoop(let r)): return l == r -+ case (.beginForInLoop(let l), .beginForInLoop(let r)): return l == r -+ case (.endForInLoop(let l), .endForInLoop(let r)): return l == r -+ case (.beginForOfLoop(let l), .beginForOfLoop(let r)): return l == r -+ case (.beginForOfLoopWithDestruct(let l), .beginForOfLoopWithDestruct(let r)): return l == r -+ case (.endForOfLoop(let l), .endForOfLoop(let r)): return l == r -+ case (.beginRepeatLoop(let l), .beginRepeatLoop(let r)): return l == r -+ case (.endRepeatLoop(let l), .endRepeatLoop(let r)): return l == r -+ case (.loopBreak(let l), .loopBreak(let r)): return l == r -+ case (.loopContinue(let l), .loopContinue(let r)): return l == r -+ case (.beginTry(let l), .beginTry(let r)): return l == r -+ case (.beginCatch(let l), .beginCatch(let r)): return l == r -+ case (.beginFinally(let l), .beginFinally(let r)): return l == r -+ case (.endTryCatchFinally(let l), .endTryCatchFinally(let r)): return l == r -+ case (.throwException(let l), .throwException(let r)): return l == r -+ case (.beginCodeString(let l), .beginCodeString(let r)): return l == r -+ case (.endCodeString(let l), .endCodeString(let r)): return l == r -+ case (.beginBlockStatement(let l), .beginBlockStatement(let r)): return l == r -+ case (.endBlockStatement(let l), .endBlockStatement(let r)): return l == r -+ case (.beginSwitch(let l), .beginSwitch(let r)): return l == r -+ case (.beginSwitchCase(let l), .beginSwitchCase(let r)): return l == r -+ case (.beginSwitchDefaultCase(let l), .beginSwitchDefaultCase(let r)): return l == r -+ case (.endSwitchCase(let l), .endSwitchCase(let r)): return l == r -+ case (.endSwitch(let l), .endSwitch(let r)): return l == r -+ case (.switchBreak(let l), .switchBreak(let r)): return l == r -+ case (.loadNewTarget(let l), .loadNewTarget(let r)): return l == r -+ case (.print(let l), .print(let r)): return l == r -+ case (.explore(let l), .explore(let r)): return l == r -+ case (.probe(let l), .probe(let r)): return l == r -+ case (.fixup(let l), .fixup(let r)): return l == r - default: return false - } - } -@@ -2379,6 +1848,8 @@ public struct Fuzzilli_Protobuf_Instruction { - } - - public init() {} -+ -+ fileprivate var _storage = _StorageClass.defaultInstance - } - - public struct Fuzzilli_Protobuf_Program { -@@ -2417,12 +1888,6 @@ public struct Fuzzilli_Protobuf_Program { - fileprivate var _storage = _StorageClass.defaultInstance - } - --#if swift(>=5.5) && canImport(_Concurrency) --extension Fuzzilli_Protobuf_Instruction: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Instruction.OneOf_Operation: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Program: @unchecked Sendable {} --#endif // swift(>=5.5) && canImport(_Concurrency) -- - // MARK: - Code below here is support for the SwiftProtobuf runtime. - - fileprivate let _protobuf_package = "fuzzilli.protobuf" -@@ -2611,3056 +2076,1839 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M - 179: .same(proto: "fixup"), - ] - -+ fileprivate class _StorageClass { -+ var _inouts: [UInt32] = [] -+ var _operation: Fuzzilli_Protobuf_Instruction.OneOf_Operation? -+ -+ static let defaultInstance = _StorageClass() -+ -+ private init() {} -+ -+ init(copying source: _StorageClass) { -+ _inouts = source._inouts -+ _operation = source._operation -+ } -+ } -+ -+ 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.decodeRepeatedUInt32Field(value: &self.inouts) }() -- case 2: try { -- var v: UInt32? -- try decoder.decodeSingularUInt32Field(value: &v) -- if let v = v { -- if self.operation != nil {try decoder.handleConflictingOneOf()} -- self.operation = .opIdx(v) -- } -- }() -- case 3: try { -- var v: Fuzzilli_Protobuf_Nop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .nop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .nop(v) -- } -- }() -- case 4: try { -- var v: Fuzzilli_Protobuf_LoadInteger? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadInteger(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadInteger(v) -- } -- }() -- case 5: try { -- var v: Fuzzilli_Protobuf_LoadBigInt? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadBigInt(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadBigInt(v) -- } -- }() -- case 6: try { -- var v: Fuzzilli_Protobuf_LoadFloat? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadFloat(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadFloat(v) -- } -- }() -- case 7: try { -- var v: Fuzzilli_Protobuf_LoadString? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadString(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadString(v) -- } -- }() -- case 8: try { -- var v: Fuzzilli_Protobuf_LoadBoolean? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadBoolean(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadBoolean(v) -- } -- }() -- case 9: try { -- var v: Fuzzilli_Protobuf_LoadUndefined? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadUndefined(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadUndefined(v) -- } -- }() -- case 10: try { -- var v: Fuzzilli_Protobuf_LoadNull? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadNull(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadNull(v) -- } -- }() -- case 11: try { -- var v: Fuzzilli_Protobuf_LoadThis? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadThis(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadThis(v) -- } -- }() -- case 12: try { -- var v: Fuzzilli_Protobuf_LoadArguments? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadArguments(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadArguments(v) -- } -- }() -- case 13: try { -- var v: Fuzzilli_Protobuf_LoadRegExp? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadRegExp(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadRegExp(v) -- } -- }() -- case 14: try { -- var v: Fuzzilli_Protobuf_BeginObjectLiteral? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginObjectLiteral(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginObjectLiteral(v) -- } -- }() -- case 15: try { -- var v: Fuzzilli_Protobuf_ObjectLiteralAddProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .objectLiteralAddProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .objectLiteralAddProperty(v) -- } -- }() -- case 16: try { -- var v: Fuzzilli_Protobuf_ObjectLiteralAddElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .objectLiteralAddElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .objectLiteralAddElement(v) -- } -- }() -- case 17: try { -- var v: Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .objectLiteralAddComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .objectLiteralAddComputedProperty(v) -- } -- }() -- case 18: try { -- var v: Fuzzilli_Protobuf_ObjectLiteralCopyProperties? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .objectLiteralCopyProperties(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .objectLiteralCopyProperties(v) -- } -- }() -- case 19: try { -- var v: Fuzzilli_Protobuf_ObjectLiteralSetPrototype? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .objectLiteralSetPrototype(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .objectLiteralSetPrototype(v) -- } -- }() -- case 20: try { -- var v: Fuzzilli_Protobuf_BeginObjectLiteralMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginObjectLiteralMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginObjectLiteralMethod(v) -- } -- }() -- case 21: try { -- var v: Fuzzilli_Protobuf_EndObjectLiteralMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endObjectLiteralMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endObjectLiteralMethod(v) -- } -- }() -- case 22: try { -- var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginObjectLiteralComputedMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginObjectLiteralComputedMethod(v) -- } -- }() -- case 23: try { -- var v: Fuzzilli_Protobuf_EndObjectLiteralComputedMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endObjectLiteralComputedMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endObjectLiteralComputedMethod(v) -- } -- }() -- case 24: try { -- var v: Fuzzilli_Protobuf_BeginObjectLiteralGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginObjectLiteralGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginObjectLiteralGetter(v) -- } -- }() -- case 25: try { -- var v: Fuzzilli_Protobuf_EndObjectLiteralGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endObjectLiteralGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endObjectLiteralGetter(v) -- } -- }() -- case 26: try { -- var v: Fuzzilli_Protobuf_BeginObjectLiteralSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginObjectLiteralSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginObjectLiteralSetter(v) -- } -- }() -- case 27: try { -- var v: Fuzzilli_Protobuf_EndObjectLiteralSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endObjectLiteralSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endObjectLiteralSetter(v) -- } -- }() -- case 28: try { -- var v: Fuzzilli_Protobuf_EndObjectLiteral? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endObjectLiteral(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endObjectLiteral(v) -- } -- }() -- case 29: try { -- var v: Fuzzilli_Protobuf_BeginClassDefinition? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassDefinition(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassDefinition(v) -- } -- }() -- case 30: try { -- var v: Fuzzilli_Protobuf_BeginClassConstructor? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassConstructor(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassConstructor(v) -- } -- }() -- case 31: try { -- var v: Fuzzilli_Protobuf_EndClassConstructor? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassConstructor(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassConstructor(v) -- } -- }() -- case 32: try { -- var v: Fuzzilli_Protobuf_ClassAddInstanceProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddInstanceProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddInstanceProperty(v) -- } -- }() -- case 33: try { -- var v: Fuzzilli_Protobuf_ClassAddInstanceElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddInstanceElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddInstanceElement(v) -- } -- }() -- case 34: try { -- var v: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddInstanceComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddInstanceComputedProperty(v) -- } -- }() -- case 35: try { -- var v: Fuzzilli_Protobuf_BeginClassInstanceMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassInstanceMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassInstanceMethod(v) -- } -- }() -- case 36: try { -- var v: Fuzzilli_Protobuf_EndClassInstanceMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassInstanceMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassInstanceMethod(v) -- } -- }() -- case 37: try { -- var v: Fuzzilli_Protobuf_BeginClassInstanceGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassInstanceGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassInstanceGetter(v) -- } -- }() -- case 38: try { -- var v: Fuzzilli_Protobuf_EndClassInstanceGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassInstanceGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassInstanceGetter(v) -- } -- }() -- case 39: try { -- var v: Fuzzilli_Protobuf_BeginClassInstanceSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassInstanceSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassInstanceSetter(v) -- } -- }() -- case 40: try { -- var v: Fuzzilli_Protobuf_EndClassInstanceSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassInstanceSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassInstanceSetter(v) -- } -- }() -- case 41: try { -- var v: Fuzzilli_Protobuf_ClassAddStaticProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddStaticProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddStaticProperty(v) -- } -- }() -- case 42: try { -- var v: Fuzzilli_Protobuf_ClassAddStaticElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddStaticElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddStaticElement(v) -- } -- }() -- case 43: try { -- var v: Fuzzilli_Protobuf_ClassAddStaticComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddStaticComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddStaticComputedProperty(v) -- } -- }() -- case 44: try { -- var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassStaticInitializer(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassStaticInitializer(v) -- } -- }() -- case 45: try { -- var v: Fuzzilli_Protobuf_EndClassStaticInitializer? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassStaticInitializer(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassStaticInitializer(v) -- } -- }() -- case 46: try { -- var v: Fuzzilli_Protobuf_BeginClassStaticMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassStaticMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassStaticMethod(v) -- } -- }() -- case 47: try { -- var v: Fuzzilli_Protobuf_EndClassStaticMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassStaticMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassStaticMethod(v) -- } -- }() -- case 48: try { -- var v: Fuzzilli_Protobuf_BeginClassStaticGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassStaticGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassStaticGetter(v) -- } -- }() -- case 49: try { -- var v: Fuzzilli_Protobuf_EndClassStaticGetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassStaticGetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassStaticGetter(v) -- } -- }() -- case 50: try { -- var v: Fuzzilli_Protobuf_BeginClassStaticSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassStaticSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassStaticSetter(v) -- } -- }() -- case 51: try { -- var v: Fuzzilli_Protobuf_EndClassStaticSetter? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassStaticSetter(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassStaticSetter(v) -- } -- }() -- case 52: try { -- var v: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddPrivateInstanceProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddPrivateInstanceProperty(v) -- } -- }() -- case 53: try { -- var v: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassPrivateInstanceMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassPrivateInstanceMethod(v) -- } -- }() -- case 54: try { -- var v: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassPrivateInstanceMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassPrivateInstanceMethod(v) -- } -- }() -- case 55: try { -- var v: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .classAddPrivateStaticProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .classAddPrivateStaticProperty(v) -- } -- }() -- case 56: try { -- var v: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginClassPrivateStaticMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginClassPrivateStaticMethod(v) -- } -- }() -- case 57: try { -- var v: Fuzzilli_Protobuf_EndClassPrivateStaticMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassPrivateStaticMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassPrivateStaticMethod(v) -- } -- }() -- case 58: try { -- var v: Fuzzilli_Protobuf_EndClassDefinition? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endClassDefinition(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endClassDefinition(v) -- } -- }() -- case 59: try { -- var v: Fuzzilli_Protobuf_CreateArray? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .createArray(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .createArray(v) -- } -- }() -- case 60: try { -- var v: Fuzzilli_Protobuf_CreateIntArray? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .createIntArray(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .createIntArray(v) -- } -- }() -- case 61: try { -- var v: Fuzzilli_Protobuf_CreateFloatArray? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .createFloatArray(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .createFloatArray(v) -- } -- }() -- case 62: try { -- var v: Fuzzilli_Protobuf_CreateArrayWithSpread? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .createArrayWithSpread(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .createArrayWithSpread(v) -- } -- }() -- case 63: try { -- var v: Fuzzilli_Protobuf_CreateTemplateString? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .createTemplateString(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .createTemplateString(v) -- } -- }() -- case 64: try { -- var v: Fuzzilli_Protobuf_LoadBuiltin? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadBuiltin(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadBuiltin(v) -- } -- }() -- case 65: try { -- var v: Fuzzilli_Protobuf_GetProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getProperty(v) -- } -- }() -- case 66: try { -- var v: Fuzzilli_Protobuf_SetProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setProperty(v) -- } -- }() -- case 67: try { -- var v: Fuzzilli_Protobuf_UpdateProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .updateProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .updateProperty(v) -- } -- }() -- case 68: try { -- var v: Fuzzilli_Protobuf_DeleteProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .deleteProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .deleteProperty(v) -- } -- }() -- case 69: try { -- var v: Fuzzilli_Protobuf_ConfigureProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .configureProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .configureProperty(v) -- } -- }() -- case 70: try { -- var v: Fuzzilli_Protobuf_GetElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getElement(v) -- } -- }() -- case 71: try { -- var v: Fuzzilli_Protobuf_SetElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setElement(v) -- } -- }() -- case 72: try { -- var v: Fuzzilli_Protobuf_UpdateElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .updateElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .updateElement(v) -- } -- }() -- case 73: try { -- var v: Fuzzilli_Protobuf_DeleteElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .deleteElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .deleteElement(v) -- } -- }() -- case 74: try { -- var v: Fuzzilli_Protobuf_ConfigureElement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .configureElement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .configureElement(v) -- } -- }() -- case 75: try { -- var v: Fuzzilli_Protobuf_GetComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getComputedProperty(v) -- } -- }() -- case 76: try { -- var v: Fuzzilli_Protobuf_SetComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setComputedProperty(v) -- } -- }() -- case 77: try { -- var v: Fuzzilli_Protobuf_UpdateComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .updateComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .updateComputedProperty(v) -- } -- }() -- case 78: try { -- var v: Fuzzilli_Protobuf_DeleteComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .deleteComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .deleteComputedProperty(v) -- } -- }() -- case 79: try { -- var v: Fuzzilli_Protobuf_ConfigureComputedProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .configureComputedProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .configureComputedProperty(v) -- } -- }() -- case 80: try { -- var v: Fuzzilli_Protobuf_TypeOf? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .typeOf(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .typeOf(v) -- } -- }() -- case 81: try { -- var v: Fuzzilli_Protobuf_TestInstanceOf? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .testInstanceOf(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .testInstanceOf(v) -- } -- }() -- case 82: 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 83: 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 84: 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 85: 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 86: 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 87: 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 88: 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 89: 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 90: 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 91: 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 92: 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 93: 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 94: 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 95: 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 96: try { -- var v: Fuzzilli_Protobuf_EndConstructor? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endConstructor(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endConstructor(v) -- } -- }() -- case 97: try { -- var v: Fuzzilli_Protobuf_Return? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .return(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .return(v) -- } -- }() -- case 98: try { -- var v: Fuzzilli_Protobuf_Yield? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .yield(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .yield(v) -- } -- }() -- case 99: try { -- var v: Fuzzilli_Protobuf_YieldEach? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .yieldEach(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .yieldEach(v) -- } -- }() -- case 100: try { -- var v: Fuzzilli_Protobuf_Await? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .await(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .await(v) -- } -- }() -- case 101: try { -- var v: Fuzzilli_Protobuf_CallFunction? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callFunction(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callFunction(v) -- } -- }() -- case 102: try { -- var v: Fuzzilli_Protobuf_CallFunctionWithSpread? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callFunctionWithSpread(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callFunctionWithSpread(v) -- } -- }() -- case 103: try { -- var v: Fuzzilli_Protobuf_Construct? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .construct(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .construct(v) -- } -- }() -- case 104: try { -- var v: Fuzzilli_Protobuf_ConstructWithSpread? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .constructWithSpread(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .constructWithSpread(v) -- } -- }() -- case 105: try { -- var v: Fuzzilli_Protobuf_CallMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callMethod(v) -- } -- }() -- case 106: try { -- var v: Fuzzilli_Protobuf_CallMethodWithSpread? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callMethodWithSpread(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callMethodWithSpread(v) -- } -- }() -- case 107: try { -- var v: Fuzzilli_Protobuf_CallComputedMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callComputedMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callComputedMethod(v) -- } -- }() -- case 108: try { -- var v: Fuzzilli_Protobuf_CallComputedMethodWithSpread? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callComputedMethodWithSpread(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callComputedMethodWithSpread(v) -- } -- }() -- case 109: try { -- var v: Fuzzilli_Protobuf_UnaryOperation? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .unaryOperation(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .unaryOperation(v) -- } -- }() -- case 110: try { -- var v: Fuzzilli_Protobuf_BinaryOperation? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .binaryOperation(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .binaryOperation(v) -- } -- }() -- case 111: try { -- var v: Fuzzilli_Protobuf_TernaryOperation? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .ternaryOperation(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .ternaryOperation(v) -- } -- }() -- case 112: try { -- var v: Fuzzilli_Protobuf_Update? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .update(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .update(v) -- } -- }() -- case 113: try { -- var v: Fuzzilli_Protobuf_Dup? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .dup(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .dup(v) -- } -- }() -- case 114: try { -- var v: Fuzzilli_Protobuf_Reassign? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .reassign(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .reassign(v) -- } -- }() -- case 115: try { -- var v: Fuzzilli_Protobuf_DestructArray? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .destructArray(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .destructArray(v) -- } -- }() -- case 116: try { -- var v: Fuzzilli_Protobuf_DestructArrayAndReassign? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .destructArrayAndReassign(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .destructArrayAndReassign(v) -- } -- }() -- case 117: try { -- var v: Fuzzilli_Protobuf_DestructObject? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .destructObject(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .destructObject(v) -- } -- }() -- case 118: try { -- var v: Fuzzilli_Protobuf_DestructObjectAndReassign? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .destructObjectAndReassign(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .destructObjectAndReassign(v) -- } -- }() -- case 119: try { -- var v: Fuzzilli_Protobuf_Compare? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .compare(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .compare(v) -- } -- }() -- case 120: try { -- var v: Fuzzilli_Protobuf_LoadNamedVariable? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadNamedVariable(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadNamedVariable(v) -- } -- }() -- case 121: try { -- var v: Fuzzilli_Protobuf_StoreNamedVariable? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .storeNamedVariable(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .storeNamedVariable(v) -- } -- }() -- case 122: try { -- var v: Fuzzilli_Protobuf_DefineNamedVariable? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .defineNamedVariable(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .defineNamedVariable(v) -- } -- }() -- case 123: try { -- var v: Fuzzilli_Protobuf_Eval? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .eval(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .eval(v) -- } -- }() -- case 124: try { -- var v: Fuzzilli_Protobuf_BeginWith? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginWith(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginWith(v) -- } -- }() -- case 125: try { -- var v: Fuzzilli_Protobuf_EndWith? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endWith(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endWith(v) -- } -- }() -- case 126: try { -- var v: Fuzzilli_Protobuf_CallSuperConstructor? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callSuperConstructor(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callSuperConstructor(v) -- } -- }() -- case 127: try { -- var v: Fuzzilli_Protobuf_CallSuperMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callSuperMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callSuperMethod(v) -- } -- }() -- case 128: try { -- var v: Fuzzilli_Protobuf_GetPrivateProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getPrivateProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getPrivateProperty(v) -- } -- }() -- case 129: try { -- var v: Fuzzilli_Protobuf_SetPrivateProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setPrivateProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setPrivateProperty(v) -- } -- }() -- case 130: try { -- var v: Fuzzilli_Protobuf_UpdatePrivateProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .updatePrivateProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .updatePrivateProperty(v) -- } -- }() -- case 131: try { -- var v: Fuzzilli_Protobuf_CallPrivateMethod? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .callPrivateMethod(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .callPrivateMethod(v) -- } -- }() -- case 132: try { -- var v: Fuzzilli_Protobuf_GetSuperProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getSuperProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getSuperProperty(v) -- } -- }() -- case 133: try { -- var v: Fuzzilli_Protobuf_SetSuperProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setSuperProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setSuperProperty(v) -- } -- }() -- case 134: try { -- var v: Fuzzilli_Protobuf_GetComputedSuperProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .getComputedSuperProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .getComputedSuperProperty(v) -- } -- }() -- case 135: try { -- var v: Fuzzilli_Protobuf_SetComputedSuperProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .setComputedSuperProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .setComputedSuperProperty(v) -- } -- }() -- case 136: try { -- var v: Fuzzilli_Protobuf_UpdateSuperProperty? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .updateSuperProperty(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .updateSuperProperty(v) -- } -- }() -- case 137: try { -- var v: Fuzzilli_Protobuf_BeginIf? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginIf(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginIf(v) -- } -- }() -- case 138: try { -- var v: Fuzzilli_Protobuf_BeginElse? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginElse(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginElse(v) -- } -- }() -- case 139: try { -- var v: Fuzzilli_Protobuf_EndIf? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endIf(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endIf(v) -- } -- }() -- case 140: try { -- var v: Fuzzilli_Protobuf_BeginWhileLoopHeader? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginWhileLoopHeader(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginWhileLoopHeader(v) -- } -- }() -- case 141: try { -- var v: Fuzzilli_Protobuf_BeginWhileLoopBody? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginWhileLoopBody(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginWhileLoopBody(v) -- } -- }() -- case 142: try { -- var v: Fuzzilli_Protobuf_EndWhileLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endWhileLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endWhileLoop(v) -- } -- }() -- case 143: try { -- var v: Fuzzilli_Protobuf_BeginDoWhileLoopBody? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginDoWhileLoopBody(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginDoWhileLoopBody(v) -- } -- }() -- case 144: try { -- var v: Fuzzilli_Protobuf_BeginDoWhileLoopHeader? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginDoWhileLoopHeader(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginDoWhileLoopHeader(v) -- } -- }() -- case 145: try { -- var v: Fuzzilli_Protobuf_EndDoWhileLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endDoWhileLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endDoWhileLoop(v) -- } -- }() -- case 146: try { -- var v: Fuzzilli_Protobuf_BeginForLoopInitializer? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForLoopInitializer(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForLoopInitializer(v) -- } -- }() -- case 147: try { -- var v: Fuzzilli_Protobuf_BeginForLoopCondition? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForLoopCondition(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForLoopCondition(v) -- } -- }() -- case 148: try { -- var v: Fuzzilli_Protobuf_BeginForLoopAfterthought? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForLoopAfterthought(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForLoopAfterthought(v) -- } -- }() -- case 149: try { -- var v: Fuzzilli_Protobuf_BeginForLoopBody? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForLoopBody(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForLoopBody(v) -- } -- }() -- case 150: try { -- var v: Fuzzilli_Protobuf_EndForLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endForLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endForLoop(v) -- } -- }() -- case 151: try { -- var v: Fuzzilli_Protobuf_BeginForInLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForInLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForInLoop(v) -- } -- }() -- case 152: try { -- var v: Fuzzilli_Protobuf_EndForInLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endForInLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endForInLoop(v) -- } -- }() -- case 153: try { -- var v: Fuzzilli_Protobuf_BeginForOfLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForOfLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForOfLoop(v) -- } -- }() -- case 154: try { -- var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginForOfLoopWithDestruct(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginForOfLoopWithDestruct(v) -- } -- }() -- case 155: try { -- var v: Fuzzilli_Protobuf_EndForOfLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endForOfLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endForOfLoop(v) -- } -- }() -- case 156: try { -- var v: Fuzzilli_Protobuf_BeginRepeatLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginRepeatLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginRepeatLoop(v) -- } -- }() -- case 157: try { -- var v: Fuzzilli_Protobuf_EndRepeatLoop? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endRepeatLoop(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endRepeatLoop(v) -- } -- }() -- case 158: try { -- var v: Fuzzilli_Protobuf_LoopBreak? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loopBreak(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loopBreak(v) -- } -- }() -- case 159: try { -- var v: Fuzzilli_Protobuf_LoopContinue? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loopContinue(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loopContinue(v) -- } -- }() -- case 160: try { -- var v: Fuzzilli_Protobuf_BeginTry? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginTry(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginTry(v) -- } -- }() -- case 161: try { -- var v: Fuzzilli_Protobuf_BeginCatch? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginCatch(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginCatch(v) -- } -- }() -- case 162: try { -- var v: Fuzzilli_Protobuf_BeginFinally? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginFinally(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginFinally(v) -- } -- }() -- case 163: try { -- var v: Fuzzilli_Protobuf_EndTryCatchFinally? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endTryCatchFinally(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endTryCatchFinally(v) -- } -- }() -- case 164: try { -- var v: Fuzzilli_Protobuf_ThrowException? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .throwException(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .throwException(v) -- } -- }() -- case 165: try { -- var v: Fuzzilli_Protobuf_BeginCodeString? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginCodeString(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginCodeString(v) -- } -- }() -- case 166: try { -- var v: Fuzzilli_Protobuf_EndCodeString? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endCodeString(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endCodeString(v) -- } -- }() -- case 167: try { -- var v: Fuzzilli_Protobuf_BeginBlockStatement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginBlockStatement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginBlockStatement(v) -- } -- }() -- case 168: try { -- var v: Fuzzilli_Protobuf_EndBlockStatement? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endBlockStatement(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endBlockStatement(v) -- } -- }() -- case 169: try { -- var v: Fuzzilli_Protobuf_BeginSwitch? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginSwitch(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginSwitch(v) -- } -- }() -- case 170: try { -- var v: Fuzzilli_Protobuf_BeginSwitchCase? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginSwitchCase(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginSwitchCase(v) -- } -- }() -- case 171: try { -- var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .beginSwitchDefaultCase(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .beginSwitchDefaultCase(v) -- } -- }() -- case 172: try { -- var v: Fuzzilli_Protobuf_EndSwitchCase? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endSwitchCase(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endSwitchCase(v) -- } -- }() -- case 173: try { -- var v: Fuzzilli_Protobuf_EndSwitch? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .endSwitch(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .endSwitch(v) -- } -- }() -- case 174: try { -- var v: Fuzzilli_Protobuf_SwitchBreak? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .switchBreak(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .switchBreak(v) -- } -- }() -- case 175: try { -- var v: Fuzzilli_Protobuf_LoadNewTarget? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .loadNewTarget(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .loadNewTarget(v) -- } -- }() -- case 176: try { -- var v: Fuzzilli_Protobuf_Print? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .print(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .print(v) -- } -- }() -- case 177: try { -- var v: Fuzzilli_Protobuf_Explore? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .explore(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .explore(v) -- } -- }() -- case 178: try { -- var v: Fuzzilli_Protobuf_Probe? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .probe(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .probe(v) -- } -- }() -- case 179: try { -- var v: Fuzzilli_Protobuf_Fixup? -- var hadOneofValue = false -- if let current = self.operation { -- hadOneofValue = true -- if case .fixup(let m) = current {v = m} -- } -- try decoder.decodeSingularMessageField(value: &v) -- if let v = v { -- if hadOneofValue {try decoder.handleConflictingOneOf()} -- self.operation = .fixup(v) -+ _ = _uniqueStorage() -+ try withExtendedLifetime(_storage) { (_storage: _StorageClass) in -+ while let fieldNumber = try decoder.nextFieldNumber() { -+ switch fieldNumber { -+ case 1: try decoder.decodeRepeatedUInt32Field(value: &_storage._inouts) -+ case 2: -+ if _storage._operation != nil {try decoder.handleConflictingOneOf()} -+ var v: UInt32? -+ try decoder.decodeSingularUInt32Field(value: &v) -+ if let v = v {_storage._operation = .opIdx(v)} -+ case 3: -+ var v: Fuzzilli_Protobuf_Nop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .nop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .nop(v)} -+ case 4: -+ var v: Fuzzilli_Protobuf_LoadInteger? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadInteger(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadInteger(v)} -+ case 5: -+ var v: Fuzzilli_Protobuf_LoadBigInt? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadBigInt(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadBigInt(v)} -+ case 6: -+ var v: Fuzzilli_Protobuf_LoadFloat? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadFloat(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadFloat(v)} -+ case 7: -+ var v: Fuzzilli_Protobuf_LoadString? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadString(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadString(v)} -+ case 8: -+ var v: Fuzzilli_Protobuf_LoadBoolean? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadBoolean(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadBoolean(v)} -+ case 9: -+ var v: Fuzzilli_Protobuf_LoadUndefined? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadUndefined(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadUndefined(v)} -+ case 10: -+ var v: Fuzzilli_Protobuf_LoadNull? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadNull(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadNull(v)} -+ case 11: -+ var v: Fuzzilli_Protobuf_LoadThis? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadThis(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadThis(v)} -+ case 12: -+ var v: Fuzzilli_Protobuf_LoadArguments? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadArguments(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadArguments(v)} -+ case 13: -+ var v: Fuzzilli_Protobuf_LoadRegExp? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadRegExp(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadRegExp(v)} -+ case 14: -+ var v: Fuzzilli_Protobuf_BeginObjectLiteral? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginObjectLiteral(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginObjectLiteral(v)} -+ case 15: -+ var v: Fuzzilli_Protobuf_ObjectLiteralAddProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .objectLiteralAddProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .objectLiteralAddProperty(v)} -+ case 16: -+ var v: Fuzzilli_Protobuf_ObjectLiteralAddElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .objectLiteralAddElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .objectLiteralAddElement(v)} -+ case 17: -+ var v: Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .objectLiteralAddComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .objectLiteralAddComputedProperty(v)} -+ case 18: -+ var v: Fuzzilli_Protobuf_ObjectLiteralCopyProperties? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .objectLiteralCopyProperties(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .objectLiteralCopyProperties(v)} -+ case 19: -+ var v: Fuzzilli_Protobuf_ObjectLiteralSetPrototype? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .objectLiteralSetPrototype(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .objectLiteralSetPrototype(v)} -+ case 20: -+ var v: Fuzzilli_Protobuf_BeginObjectLiteralMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginObjectLiteralMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginObjectLiteralMethod(v)} -+ case 21: -+ var v: Fuzzilli_Protobuf_EndObjectLiteralMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endObjectLiteralMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endObjectLiteralMethod(v)} -+ case 22: -+ var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginObjectLiteralComputedMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginObjectLiteralComputedMethod(v)} -+ case 23: -+ var v: Fuzzilli_Protobuf_EndObjectLiteralComputedMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endObjectLiteralComputedMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endObjectLiteralComputedMethod(v)} -+ case 24: -+ var v: Fuzzilli_Protobuf_BeginObjectLiteralGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginObjectLiteralGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginObjectLiteralGetter(v)} -+ case 25: -+ var v: Fuzzilli_Protobuf_EndObjectLiteralGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endObjectLiteralGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endObjectLiteralGetter(v)} -+ case 26: -+ var v: Fuzzilli_Protobuf_BeginObjectLiteralSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginObjectLiteralSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginObjectLiteralSetter(v)} -+ case 27: -+ var v: Fuzzilli_Protobuf_EndObjectLiteralSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endObjectLiteralSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endObjectLiteralSetter(v)} -+ case 28: -+ var v: Fuzzilli_Protobuf_EndObjectLiteral? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endObjectLiteral(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endObjectLiteral(v)} -+ case 29: -+ var v: Fuzzilli_Protobuf_BeginClassDefinition? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassDefinition(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassDefinition(v)} -+ case 30: -+ var v: Fuzzilli_Protobuf_BeginClassConstructor? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassConstructor(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassConstructor(v)} -+ case 31: -+ var v: Fuzzilli_Protobuf_EndClassConstructor? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassConstructor(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassConstructor(v)} -+ case 32: -+ var v: Fuzzilli_Protobuf_ClassAddInstanceProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddInstanceProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddInstanceProperty(v)} -+ case 33: -+ var v: Fuzzilli_Protobuf_ClassAddInstanceElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddInstanceElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddInstanceElement(v)} -+ case 34: -+ var v: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddInstanceComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddInstanceComputedProperty(v)} -+ case 35: -+ var v: Fuzzilli_Protobuf_BeginClassInstanceMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassInstanceMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassInstanceMethod(v)} -+ case 36: -+ var v: Fuzzilli_Protobuf_EndClassInstanceMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassInstanceMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassInstanceMethod(v)} -+ case 37: -+ var v: Fuzzilli_Protobuf_BeginClassInstanceGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassInstanceGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassInstanceGetter(v)} -+ case 38: -+ var v: Fuzzilli_Protobuf_EndClassInstanceGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassInstanceGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassInstanceGetter(v)} -+ case 39: -+ var v: Fuzzilli_Protobuf_BeginClassInstanceSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassInstanceSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassInstanceSetter(v)} -+ case 40: -+ var v: Fuzzilli_Protobuf_EndClassInstanceSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassInstanceSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassInstanceSetter(v)} -+ case 41: -+ var v: Fuzzilli_Protobuf_ClassAddStaticProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddStaticProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddStaticProperty(v)} -+ case 42: -+ var v: Fuzzilli_Protobuf_ClassAddStaticElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddStaticElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddStaticElement(v)} -+ case 43: -+ var v: Fuzzilli_Protobuf_ClassAddStaticComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddStaticComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddStaticComputedProperty(v)} -+ case 44: -+ var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassStaticInitializer(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassStaticInitializer(v)} -+ case 45: -+ var v: Fuzzilli_Protobuf_EndClassStaticInitializer? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassStaticInitializer(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassStaticInitializer(v)} -+ case 46: -+ var v: Fuzzilli_Protobuf_BeginClassStaticMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassStaticMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassStaticMethod(v)} -+ case 47: -+ var v: Fuzzilli_Protobuf_EndClassStaticMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassStaticMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassStaticMethod(v)} -+ case 48: -+ var v: Fuzzilli_Protobuf_BeginClassStaticGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassStaticGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassStaticGetter(v)} -+ case 49: -+ var v: Fuzzilli_Protobuf_EndClassStaticGetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassStaticGetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassStaticGetter(v)} -+ case 50: -+ var v: Fuzzilli_Protobuf_BeginClassStaticSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassStaticSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassStaticSetter(v)} -+ case 51: -+ var v: Fuzzilli_Protobuf_EndClassStaticSetter? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassStaticSetter(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassStaticSetter(v)} -+ case 52: -+ var v: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddPrivateInstanceProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddPrivateInstanceProperty(v)} -+ case 53: -+ var v: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassPrivateInstanceMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassPrivateInstanceMethod(v)} -+ case 54: -+ var v: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassPrivateInstanceMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassPrivateInstanceMethod(v)} -+ case 55: -+ var v: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .classAddPrivateStaticProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .classAddPrivateStaticProperty(v)} -+ case 56: -+ var v: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginClassPrivateStaticMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginClassPrivateStaticMethod(v)} -+ case 57: -+ var v: Fuzzilli_Protobuf_EndClassPrivateStaticMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassPrivateStaticMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassPrivateStaticMethod(v)} -+ case 58: -+ var v: Fuzzilli_Protobuf_EndClassDefinition? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endClassDefinition(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endClassDefinition(v)} -+ case 59: -+ var v: Fuzzilli_Protobuf_CreateArray? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .createArray(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .createArray(v)} -+ case 60: -+ var v: Fuzzilli_Protobuf_CreateIntArray? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .createIntArray(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .createIntArray(v)} -+ case 61: -+ var v: Fuzzilli_Protobuf_CreateFloatArray? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .createFloatArray(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .createFloatArray(v)} -+ case 62: -+ var v: Fuzzilli_Protobuf_CreateArrayWithSpread? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .createArrayWithSpread(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .createArrayWithSpread(v)} -+ case 63: -+ var v: Fuzzilli_Protobuf_CreateTemplateString? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .createTemplateString(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .createTemplateString(v)} -+ case 64: -+ var v: Fuzzilli_Protobuf_LoadBuiltin? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadBuiltin(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadBuiltin(v)} -+ case 65: -+ var v: Fuzzilli_Protobuf_GetProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getProperty(v)} -+ case 66: -+ var v: Fuzzilli_Protobuf_SetProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setProperty(v)} -+ case 67: -+ var v: Fuzzilli_Protobuf_UpdateProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .updateProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .updateProperty(v)} -+ case 68: -+ var v: Fuzzilli_Protobuf_DeleteProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .deleteProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .deleteProperty(v)} -+ case 69: -+ var v: Fuzzilli_Protobuf_ConfigureProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .configureProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .configureProperty(v)} -+ case 70: -+ var v: Fuzzilli_Protobuf_GetElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getElement(v)} -+ case 71: -+ var v: Fuzzilli_Protobuf_SetElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setElement(v)} -+ case 72: -+ var v: Fuzzilli_Protobuf_UpdateElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .updateElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .updateElement(v)} -+ case 73: -+ var v: Fuzzilli_Protobuf_DeleteElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .deleteElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .deleteElement(v)} -+ case 74: -+ var v: Fuzzilli_Protobuf_ConfigureElement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .configureElement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .configureElement(v)} -+ case 75: -+ var v: Fuzzilli_Protobuf_GetComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getComputedProperty(v)} -+ case 76: -+ var v: Fuzzilli_Protobuf_SetComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setComputedProperty(v)} -+ case 77: -+ var v: Fuzzilli_Protobuf_UpdateComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .updateComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .updateComputedProperty(v)} -+ case 78: -+ var v: Fuzzilli_Protobuf_DeleteComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .deleteComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .deleteComputedProperty(v)} -+ case 79: -+ var v: Fuzzilli_Protobuf_ConfigureComputedProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .configureComputedProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .configureComputedProperty(v)} -+ case 80: -+ var v: Fuzzilli_Protobuf_TypeOf? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .typeOf(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .typeOf(v)} -+ case 81: -+ var v: Fuzzilli_Protobuf_TestInstanceOf? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .testInstanceOf(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .testInstanceOf(v)} -+ case 82: -+ var v: Fuzzilli_Protobuf_TestIn? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .testIn(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .testIn(v)} -+ case 83: -+ var v: Fuzzilli_Protobuf_BeginPlainFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginPlainFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginPlainFunction(v)} -+ case 84: -+ var v: Fuzzilli_Protobuf_EndPlainFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endPlainFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endPlainFunction(v)} -+ case 85: -+ var v: Fuzzilli_Protobuf_BeginArrowFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginArrowFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginArrowFunction(v)} -+ case 86: -+ var v: Fuzzilli_Protobuf_EndArrowFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endArrowFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endArrowFunction(v)} -+ case 87: -+ var v: Fuzzilli_Protobuf_BeginGeneratorFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginGeneratorFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginGeneratorFunction(v)} -+ case 88: -+ var v: Fuzzilli_Protobuf_EndGeneratorFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endGeneratorFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endGeneratorFunction(v)} -+ case 89: -+ var v: Fuzzilli_Protobuf_BeginAsyncFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginAsyncFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginAsyncFunction(v)} -+ case 90: -+ var v: Fuzzilli_Protobuf_EndAsyncFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endAsyncFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endAsyncFunction(v)} -+ case 91: -+ var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginAsyncArrowFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginAsyncArrowFunction(v)} -+ case 92: -+ var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endAsyncArrowFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endAsyncArrowFunction(v)} -+ case 93: -+ var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginAsyncGeneratorFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginAsyncGeneratorFunction(v)} -+ case 94: -+ var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endAsyncGeneratorFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endAsyncGeneratorFunction(v)} -+ case 95: -+ var v: Fuzzilli_Protobuf_BeginConstructor? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginConstructor(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginConstructor(v)} -+ case 96: -+ var v: Fuzzilli_Protobuf_EndConstructor? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endConstructor(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endConstructor(v)} -+ case 97: -+ var v: Fuzzilli_Protobuf_Return? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .return(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .return(v)} -+ case 98: -+ var v: Fuzzilli_Protobuf_Yield? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .yield(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .yield(v)} -+ case 99: -+ var v: Fuzzilli_Protobuf_YieldEach? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .yieldEach(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .yieldEach(v)} -+ case 100: -+ var v: Fuzzilli_Protobuf_Await? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .await(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .await(v)} -+ case 101: -+ var v: Fuzzilli_Protobuf_CallFunction? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callFunction(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callFunction(v)} -+ case 102: -+ var v: Fuzzilli_Protobuf_CallFunctionWithSpread? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callFunctionWithSpread(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callFunctionWithSpread(v)} -+ case 103: -+ var v: Fuzzilli_Protobuf_Construct? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .construct(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .construct(v)} -+ case 104: -+ var v: Fuzzilli_Protobuf_ConstructWithSpread? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .constructWithSpread(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .constructWithSpread(v)} -+ case 105: -+ var v: Fuzzilli_Protobuf_CallMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callMethod(v)} -+ case 106: -+ var v: Fuzzilli_Protobuf_CallMethodWithSpread? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callMethodWithSpread(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callMethodWithSpread(v)} -+ case 107: -+ var v: Fuzzilli_Protobuf_CallComputedMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callComputedMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callComputedMethod(v)} -+ case 108: -+ var v: Fuzzilli_Protobuf_CallComputedMethodWithSpread? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callComputedMethodWithSpread(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callComputedMethodWithSpread(v)} -+ case 109: -+ var v: Fuzzilli_Protobuf_UnaryOperation? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .unaryOperation(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .unaryOperation(v)} -+ case 110: -+ var v: Fuzzilli_Protobuf_BinaryOperation? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .binaryOperation(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .binaryOperation(v)} -+ case 111: -+ var v: Fuzzilli_Protobuf_TernaryOperation? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .ternaryOperation(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .ternaryOperation(v)} -+ case 112: -+ var v: Fuzzilli_Protobuf_Update? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .update(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .update(v)} -+ case 113: -+ var v: Fuzzilli_Protobuf_Dup? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .dup(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .dup(v)} -+ case 114: -+ var v: Fuzzilli_Protobuf_Reassign? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .reassign(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .reassign(v)} -+ case 115: -+ var v: Fuzzilli_Protobuf_DestructArray? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .destructArray(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .destructArray(v)} -+ case 116: -+ var v: Fuzzilli_Protobuf_DestructArrayAndReassign? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .destructArrayAndReassign(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .destructArrayAndReassign(v)} -+ case 117: -+ var v: Fuzzilli_Protobuf_DestructObject? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .destructObject(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .destructObject(v)} -+ case 118: -+ var v: Fuzzilli_Protobuf_DestructObjectAndReassign? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .destructObjectAndReassign(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .destructObjectAndReassign(v)} -+ case 119: -+ var v: Fuzzilli_Protobuf_Compare? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .compare(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .compare(v)} -+ case 120: -+ var v: Fuzzilli_Protobuf_LoadNamedVariable? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadNamedVariable(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadNamedVariable(v)} -+ case 121: -+ var v: Fuzzilli_Protobuf_StoreNamedVariable? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .storeNamedVariable(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .storeNamedVariable(v)} -+ case 122: -+ var v: Fuzzilli_Protobuf_DefineNamedVariable? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .defineNamedVariable(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .defineNamedVariable(v)} -+ case 123: -+ var v: Fuzzilli_Protobuf_Eval? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .eval(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .eval(v)} -+ case 124: -+ var v: Fuzzilli_Protobuf_BeginWith? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginWith(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginWith(v)} -+ case 125: -+ var v: Fuzzilli_Protobuf_EndWith? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endWith(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endWith(v)} -+ case 126: -+ var v: Fuzzilli_Protobuf_CallSuperConstructor? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callSuperConstructor(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callSuperConstructor(v)} -+ case 127: -+ var v: Fuzzilli_Protobuf_CallSuperMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callSuperMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callSuperMethod(v)} -+ case 128: -+ var v: Fuzzilli_Protobuf_GetPrivateProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getPrivateProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getPrivateProperty(v)} -+ case 129: -+ var v: Fuzzilli_Protobuf_SetPrivateProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setPrivateProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setPrivateProperty(v)} -+ case 130: -+ var v: Fuzzilli_Protobuf_UpdatePrivateProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .updatePrivateProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .updatePrivateProperty(v)} -+ case 131: -+ var v: Fuzzilli_Protobuf_CallPrivateMethod? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .callPrivateMethod(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .callPrivateMethod(v)} -+ case 132: -+ var v: Fuzzilli_Protobuf_GetSuperProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getSuperProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getSuperProperty(v)} -+ case 133: -+ var v: Fuzzilli_Protobuf_SetSuperProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setSuperProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setSuperProperty(v)} -+ case 134: -+ var v: Fuzzilli_Protobuf_GetComputedSuperProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .getComputedSuperProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .getComputedSuperProperty(v)} -+ case 135: -+ var v: Fuzzilli_Protobuf_SetComputedSuperProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .setComputedSuperProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .setComputedSuperProperty(v)} -+ case 136: -+ var v: Fuzzilli_Protobuf_UpdateSuperProperty? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .updateSuperProperty(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .updateSuperProperty(v)} -+ case 137: -+ var v: Fuzzilli_Protobuf_BeginIf? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginIf(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginIf(v)} -+ case 138: -+ var v: Fuzzilli_Protobuf_BeginElse? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginElse(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginElse(v)} -+ case 139: -+ var v: Fuzzilli_Protobuf_EndIf? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endIf(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endIf(v)} -+ case 140: -+ var v: Fuzzilli_Protobuf_BeginWhileLoopHeader? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginWhileLoopHeader(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginWhileLoopHeader(v)} -+ case 141: -+ var v: Fuzzilli_Protobuf_BeginWhileLoopBody? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginWhileLoopBody(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginWhileLoopBody(v)} -+ case 142: -+ var v: Fuzzilli_Protobuf_EndWhileLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endWhileLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endWhileLoop(v)} -+ case 143: -+ var v: Fuzzilli_Protobuf_BeginDoWhileLoopBody? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginDoWhileLoopBody(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginDoWhileLoopBody(v)} -+ case 144: -+ var v: Fuzzilli_Protobuf_BeginDoWhileLoopHeader? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginDoWhileLoopHeader(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginDoWhileLoopHeader(v)} -+ case 145: -+ var v: Fuzzilli_Protobuf_EndDoWhileLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endDoWhileLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endDoWhileLoop(v)} -+ case 146: -+ var v: Fuzzilli_Protobuf_BeginForLoopInitializer? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForLoopInitializer(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForLoopInitializer(v)} -+ case 147: -+ var v: Fuzzilli_Protobuf_BeginForLoopCondition? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForLoopCondition(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForLoopCondition(v)} -+ case 148: -+ var v: Fuzzilli_Protobuf_BeginForLoopAfterthought? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForLoopAfterthought(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForLoopAfterthought(v)} -+ case 149: -+ var v: Fuzzilli_Protobuf_BeginForLoopBody? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForLoopBody(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForLoopBody(v)} -+ case 150: -+ var v: Fuzzilli_Protobuf_EndForLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endForLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endForLoop(v)} -+ case 151: -+ var v: Fuzzilli_Protobuf_BeginForInLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForInLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForInLoop(v)} -+ case 152: -+ var v: Fuzzilli_Protobuf_EndForInLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endForInLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endForInLoop(v)} -+ case 153: -+ var v: Fuzzilli_Protobuf_BeginForOfLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForOfLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForOfLoop(v)} -+ case 154: -+ var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginForOfLoopWithDestruct(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginForOfLoopWithDestruct(v)} -+ case 155: -+ var v: Fuzzilli_Protobuf_EndForOfLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endForOfLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endForOfLoop(v)} -+ case 156: -+ var v: Fuzzilli_Protobuf_BeginRepeatLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginRepeatLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginRepeatLoop(v)} -+ case 157: -+ var v: Fuzzilli_Protobuf_EndRepeatLoop? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endRepeatLoop(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endRepeatLoop(v)} -+ case 158: -+ var v: Fuzzilli_Protobuf_LoopBreak? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loopBreak(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loopBreak(v)} -+ case 159: -+ var v: Fuzzilli_Protobuf_LoopContinue? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loopContinue(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loopContinue(v)} -+ case 160: -+ var v: Fuzzilli_Protobuf_BeginTry? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginTry(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginTry(v)} -+ case 161: -+ var v: Fuzzilli_Protobuf_BeginCatch? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginCatch(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginCatch(v)} -+ case 162: -+ var v: Fuzzilli_Protobuf_BeginFinally? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginFinally(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginFinally(v)} -+ case 163: -+ var v: Fuzzilli_Protobuf_EndTryCatchFinally? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endTryCatchFinally(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endTryCatchFinally(v)} -+ case 164: -+ var v: Fuzzilli_Protobuf_ThrowException? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .throwException(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .throwException(v)} -+ case 165: -+ var v: Fuzzilli_Protobuf_BeginCodeString? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginCodeString(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginCodeString(v)} -+ case 166: -+ var v: Fuzzilli_Protobuf_EndCodeString? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endCodeString(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endCodeString(v)} -+ case 167: -+ var v: Fuzzilli_Protobuf_BeginBlockStatement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginBlockStatement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginBlockStatement(v)} -+ case 168: -+ var v: Fuzzilli_Protobuf_EndBlockStatement? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endBlockStatement(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endBlockStatement(v)} -+ case 169: -+ var v: Fuzzilli_Protobuf_BeginSwitch? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginSwitch(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginSwitch(v)} -+ case 170: -+ var v: Fuzzilli_Protobuf_BeginSwitchCase? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginSwitchCase(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginSwitchCase(v)} -+ case 171: -+ var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .beginSwitchDefaultCase(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .beginSwitchDefaultCase(v)} -+ case 172: -+ var v: Fuzzilli_Protobuf_EndSwitchCase? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endSwitchCase(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endSwitchCase(v)} -+ case 173: -+ var v: Fuzzilli_Protobuf_EndSwitch? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .endSwitch(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .endSwitch(v)} -+ case 174: -+ var v: Fuzzilli_Protobuf_SwitchBreak? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .switchBreak(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .switchBreak(v)} -+ case 175: -+ var v: Fuzzilli_Protobuf_LoadNewTarget? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .loadNewTarget(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .loadNewTarget(v)} -+ case 176: -+ var v: Fuzzilli_Protobuf_Print? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .print(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .print(v)} -+ case 177: -+ var v: Fuzzilli_Protobuf_Explore? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .explore(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .explore(v)} -+ case 178: -+ var v: Fuzzilli_Protobuf_Probe? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .probe(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .probe(v)} -+ case 179: -+ var v: Fuzzilli_Protobuf_Fixup? -+ if let current = _storage._operation { -+ try decoder.handleConflictingOneOf() -+ if case .fixup(let m) = current {v = m} -+ } -+ try decoder.decodeSingularMessageField(value: &v) -+ if let v = v {_storage._operation = .fixup(v)} -+ default: break - } -- }() -- 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.inouts.isEmpty { -- try visitor.visitPackedUInt32Field(value: self.inouts, fieldNumber: 1) -- } -- switch self.operation { -- case .opIdx?: try { -- guard case .opIdx(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) -- }() -- case .nop?: try { -- guard case .nop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 3) -- }() -- case .loadInteger?: try { -- guard case .loadInteger(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 4) -- }() -- case .loadBigInt?: try { -- guard case .loadBigInt(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 5) -- }() -- case .loadFloat?: try { -- guard case .loadFloat(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 6) -- }() -- case .loadString?: try { -- guard case .loadString(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 7) -- }() -- case .loadBoolean?: try { -- guard case .loadBoolean(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 8) -- }() -- case .loadUndefined?: try { -- guard case .loadUndefined(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 9) -- }() -- case .loadNull?: try { -- guard case .loadNull(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 10) -- }() -- case .loadThis?: try { -- guard case .loadThis(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 11) -- }() -- case .loadArguments?: try { -- guard case .loadArguments(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 12) -- }() -- case .loadRegExp?: try { -- guard case .loadRegExp(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 13) -- }() -- case .beginObjectLiteral?: try { -- guard case .beginObjectLiteral(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 14) -- }() -- case .objectLiteralAddProperty?: try { -- guard case .objectLiteralAddProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 15) -- }() -- case .objectLiteralAddElement?: try { -- guard case .objectLiteralAddElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 16) -- }() -- case .objectLiteralAddComputedProperty?: try { -- guard case .objectLiteralAddComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 17) -- }() -- case .objectLiteralCopyProperties?: try { -- guard case .objectLiteralCopyProperties(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 18) -- }() -- case .objectLiteralSetPrototype?: try { -- guard case .objectLiteralSetPrototype(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 19) -- }() -- case .beginObjectLiteralMethod?: try { -- guard case .beginObjectLiteralMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 20) -- }() -- case .endObjectLiteralMethod?: try { -- guard case .endObjectLiteralMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 21) -- }() -- case .beginObjectLiteralComputedMethod?: try { -- guard case .beginObjectLiteralComputedMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 22) -- }() -- case .endObjectLiteralComputedMethod?: try { -- guard case .endObjectLiteralComputedMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 23) -- }() -- case .beginObjectLiteralGetter?: try { -- guard case .beginObjectLiteralGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 24) -- }() -- case .endObjectLiteralGetter?: try { -- guard case .endObjectLiteralGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 25) -- }() -- case .beginObjectLiteralSetter?: try { -- guard case .beginObjectLiteralSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 26) -- }() -- case .endObjectLiteralSetter?: try { -- guard case .endObjectLiteralSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 27) -- }() -- case .endObjectLiteral?: try { -- guard case .endObjectLiteral(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 28) -- }() -- case .beginClassDefinition?: try { -- guard case .beginClassDefinition(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 29) -- }() -- case .beginClassConstructor?: try { -- guard case .beginClassConstructor(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 30) -- }() -- case .endClassConstructor?: try { -- guard case .endClassConstructor(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 31) -- }() -- case .classAddInstanceProperty?: try { -- guard case .classAddInstanceProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 32) -- }() -- case .classAddInstanceElement?: try { -- guard case .classAddInstanceElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 33) -- }() -- case .classAddInstanceComputedProperty?: try { -- guard case .classAddInstanceComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 34) -- }() -- case .beginClassInstanceMethod?: try { -- guard case .beginClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 35) -- }() -- case .endClassInstanceMethod?: try { -- guard case .endClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 36) -- }() -- case .beginClassInstanceGetter?: try { -- guard case .beginClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 37) -- }() -- case .endClassInstanceGetter?: try { -- guard case .endClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 38) -- }() -- case .beginClassInstanceSetter?: try { -- guard case .beginClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 39) -- }() -- case .endClassInstanceSetter?: try { -- guard case .endClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 40) -- }() -- case .classAddStaticProperty?: try { -- guard case .classAddStaticProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 41) -- }() -- case .classAddStaticElement?: try { -- guard case .classAddStaticElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 42) -- }() -- case .classAddStaticComputedProperty?: try { -- guard case .classAddStaticComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 43) -- }() -- case .beginClassStaticInitializer?: try { -- guard case .beginClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 44) -- }() -- case .endClassStaticInitializer?: try { -- guard case .endClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 45) -- }() -- case .beginClassStaticMethod?: try { -- guard case .beginClassStaticMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 46) -- }() -- case .endClassStaticMethod?: try { -- guard case .endClassStaticMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 47) -- }() -- case .beginClassStaticGetter?: try { -- guard case .beginClassStaticGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 48) -- }() -- case .endClassStaticGetter?: try { -- guard case .endClassStaticGetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 49) -- }() -- case .beginClassStaticSetter?: try { -- guard case .beginClassStaticSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 50) -- }() -- case .endClassStaticSetter?: try { -- guard case .endClassStaticSetter(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 51) -- }() -- case .classAddPrivateInstanceProperty?: try { -- guard case .classAddPrivateInstanceProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 52) -- }() -- case .beginClassPrivateInstanceMethod?: try { -- guard case .beginClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 53) -- }() -- case .endClassPrivateInstanceMethod?: try { -- guard case .endClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 54) -- }() -- case .classAddPrivateStaticProperty?: try { -- guard case .classAddPrivateStaticProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 55) -- }() -- case .beginClassPrivateStaticMethod?: try { -- guard case .beginClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 56) -- }() -- case .endClassPrivateStaticMethod?: try { -- guard case .endClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 57) -- }() -- case .endClassDefinition?: try { -- guard case .endClassDefinition(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 58) -- }() -- case .createArray?: try { -- guard case .createArray(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 59) -- }() -- case .createIntArray?: try { -- guard case .createIntArray(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 60) -- }() -- case .createFloatArray?: try { -- guard case .createFloatArray(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 61) -- }() -- case .createArrayWithSpread?: try { -- guard case .createArrayWithSpread(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 62) -- }() -- case .createTemplateString?: try { -- guard case .createTemplateString(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 63) -- }() -- case .loadBuiltin?: try { -- guard case .loadBuiltin(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 64) -- }() -- case .getProperty?: try { -- guard case .getProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 65) -- }() -- case .setProperty?: try { -- guard case .setProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 66) -- }() -- case .updateProperty?: try { -- guard case .updateProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 67) -- }() -- case .deleteProperty?: try { -- guard case .deleteProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 68) -- }() -- case .configureProperty?: try { -- guard case .configureProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 69) -- }() -- case .getElement?: try { -- guard case .getElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 70) -- }() -- case .setElement?: try { -- guard case .setElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 71) -- }() -- case .updateElement?: try { -- guard case .updateElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 72) -- }() -- case .deleteElement?: try { -- guard case .deleteElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 73) -- }() -- case .configureElement?: try { -- guard case .configureElement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 74) -- }() -- case .getComputedProperty?: try { -- guard case .getComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 75) -- }() -- case .setComputedProperty?: try { -- guard case .setComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 76) -- }() -- case .updateComputedProperty?: try { -- guard case .updateComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 77) -- }() -- case .deleteComputedProperty?: try { -- guard case .deleteComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 78) -- }() -- case .configureComputedProperty?: try { -- guard case .configureComputedProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 79) -- }() -- case .typeOf?: try { -- guard case .typeOf(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 80) -- }() -- case .testInstanceOf?: try { -- guard case .testInstanceOf(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 81) -- }() -- case .testIn?: try { -- guard case .testIn(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 82) -- }() -- case .beginPlainFunction?: try { -- guard case .beginPlainFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 83) -- }() -- case .endPlainFunction?: try { -- guard case .endPlainFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 84) -- }() -- case .beginArrowFunction?: try { -- guard case .beginArrowFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 85) -- }() -- case .endArrowFunction?: try { -- guard case .endArrowFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 86) -- }() -- case .beginGeneratorFunction?: try { -- guard case .beginGeneratorFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 87) -- }() -- case .endGeneratorFunction?: try { -- guard case .endGeneratorFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 88) -- }() -- case .beginAsyncFunction?: try { -- guard case .beginAsyncFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 89) -- }() -- case .endAsyncFunction?: try { -- guard case .endAsyncFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 90) -- }() -- case .beginAsyncArrowFunction?: try { -- guard case .beginAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 91) -- }() -- case .endAsyncArrowFunction?: try { -- guard case .endAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 92) -- }() -- case .beginAsyncGeneratorFunction?: try { -- guard case .beginAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 93) -- }() -- case .endAsyncGeneratorFunction?: try { -- guard case .endAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 94) -- }() -- case .beginConstructor?: try { -- guard case .beginConstructor(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 95) -- }() -- case .endConstructor?: try { -- guard case .endConstructor(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 96) -- }() -- case .return?: try { -- guard case .return(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 97) -- }() -- case .yield?: try { -- guard case .yield(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 98) -- }() -- case .yieldEach?: try { -- guard case .yieldEach(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 99) -- }() -- case .await?: try { -- guard case .await(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 100) -- }() -- case .callFunction?: try { -- guard case .callFunction(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 101) -- }() -- case .callFunctionWithSpread?: try { -- guard case .callFunctionWithSpread(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 102) -- }() -- case .construct?: try { -- guard case .construct(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 103) -- }() -- case .constructWithSpread?: try { -- guard case .constructWithSpread(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 104) -- }() -- case .callMethod?: try { -- guard case .callMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 105) -- }() -- case .callMethodWithSpread?: try { -- guard case .callMethodWithSpread(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 106) -- }() -- case .callComputedMethod?: try { -- guard case .callComputedMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 107) -- }() -- case .callComputedMethodWithSpread?: try { -- guard case .callComputedMethodWithSpread(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 108) -- }() -- case .unaryOperation?: try { -- guard case .unaryOperation(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 109) -- }() -- case .binaryOperation?: try { -- guard case .binaryOperation(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 110) -- }() -- case .ternaryOperation?: try { -- guard case .ternaryOperation(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 111) -- }() -- case .update?: try { -- guard case .update(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 112) -- }() -- case .dup?: try { -- guard case .dup(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 113) -- }() -- case .reassign?: try { -- guard case .reassign(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 114) -- }() -- case .destructArray?: try { -- guard case .destructArray(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 115) -- }() -- case .destructArrayAndReassign?: try { -- guard case .destructArrayAndReassign(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 116) -- }() -- case .destructObject?: try { -- guard case .destructObject(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 117) -- }() -- case .destructObjectAndReassign?: try { -- guard case .destructObjectAndReassign(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 118) -- }() -- case .compare?: try { -- guard case .compare(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 119) -- }() -- case .loadNamedVariable?: try { -- guard case .loadNamedVariable(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 120) -- }() -- case .storeNamedVariable?: try { -- guard case .storeNamedVariable(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 121) -- }() -- case .defineNamedVariable?: try { -- guard case .defineNamedVariable(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 122) -- }() -- case .eval?: try { -- guard case .eval(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 123) -- }() -- case .beginWith?: try { -- guard case .beginWith(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 124) -- }() -- case .endWith?: try { -- guard case .endWith(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 125) -- }() -- case .callSuperConstructor?: try { -- guard case .callSuperConstructor(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 126) -- }() -- case .callSuperMethod?: try { -- guard case .callSuperMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 127) -- }() -- case .getPrivateProperty?: try { -- guard case .getPrivateProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 128) -- }() -- case .setPrivateProperty?: try { -- guard case .setPrivateProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 129) -- }() -- case .updatePrivateProperty?: try { -- guard case .updatePrivateProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 130) -- }() -- case .callPrivateMethod?: try { -- guard case .callPrivateMethod(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 131) -- }() -- case .getSuperProperty?: try { -- guard case .getSuperProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 132) -- }() -- case .setSuperProperty?: try { -- guard case .setSuperProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 133) -- }() -- case .getComputedSuperProperty?: try { -- guard case .getComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 134) -- }() -- case .setComputedSuperProperty?: try { -- guard case .setComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 135) -- }() -- case .updateSuperProperty?: try { -- guard case .updateSuperProperty(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 136) -- }() -- case .beginIf?: try { -- guard case .beginIf(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 137) -- }() -- case .beginElse?: try { -- guard case .beginElse(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 138) -- }() -- case .endIf?: try { -- guard case .endIf(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 139) -- }() -- case .beginWhileLoopHeader?: try { -- guard case .beginWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 140) -- }() -- case .beginWhileLoopBody?: try { -- guard case .beginWhileLoopBody(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 141) -- }() -- case .endWhileLoop?: try { -- guard case .endWhileLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 142) -- }() -- case .beginDoWhileLoopBody?: try { -- guard case .beginDoWhileLoopBody(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 143) -- }() -- case .beginDoWhileLoopHeader?: try { -- guard case .beginDoWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 144) -- }() -- case .endDoWhileLoop?: try { -- guard case .endDoWhileLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 145) -- }() -- case .beginForLoopInitializer?: try { -- guard case .beginForLoopInitializer(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 146) -- }() -- case .beginForLoopCondition?: try { -- guard case .beginForLoopCondition(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 147) -- }() -- case .beginForLoopAfterthought?: try { -- guard case .beginForLoopAfterthought(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 148) -- }() -- case .beginForLoopBody?: try { -- guard case .beginForLoopBody(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 149) -- }() -- case .endForLoop?: try { -- guard case .endForLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 150) -- }() -- case .beginForInLoop?: try { -- guard case .beginForInLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 151) -- }() -- case .endForInLoop?: try { -- guard case .endForInLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 152) -- }() -- case .beginForOfLoop?: try { -- guard case .beginForOfLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 153) -- }() -- case .beginForOfLoopWithDestruct?: try { -- guard case .beginForOfLoopWithDestruct(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 154) -- }() -- case .endForOfLoop?: try { -- guard case .endForOfLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 155) -- }() -- case .beginRepeatLoop?: try { -- guard case .beginRepeatLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 156) -- }() -- case .endRepeatLoop?: try { -- guard case .endRepeatLoop(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 157) -- }() -- case .loopBreak?: try { -- guard case .loopBreak(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 158) -- }() -- case .loopContinue?: try { -- guard case .loopContinue(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 159) -- }() -- case .beginTry?: try { -- guard case .beginTry(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 160) -- }() -- case .beginCatch?: try { -- guard case .beginCatch(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 161) -- }() -- case .beginFinally?: try { -- guard case .beginFinally(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 162) -- }() -- case .endTryCatchFinally?: try { -- guard case .endTryCatchFinally(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 163) -- }() -- case .throwException?: try { -- guard case .throwException(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 164) -- }() -- case .beginCodeString?: try { -- guard case .beginCodeString(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 165) -- }() -- case .endCodeString?: try { -- guard case .endCodeString(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 166) -- }() -- case .beginBlockStatement?: try { -- guard case .beginBlockStatement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 167) -- }() -- case .endBlockStatement?: try { -- guard case .endBlockStatement(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 168) -- }() -- case .beginSwitch?: try { -- guard case .beginSwitch(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 169) -- }() -- case .beginSwitchCase?: try { -- guard case .beginSwitchCase(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 170) -- }() -- case .beginSwitchDefaultCase?: try { -- guard case .beginSwitchDefaultCase(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 171) -- }() -- case .endSwitchCase?: try { -- guard case .endSwitchCase(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 172) -- }() -- case .endSwitch?: try { -- guard case .endSwitch(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 173) -- }() -- case .switchBreak?: try { -- guard case .switchBreak(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 174) -- }() -- case .loadNewTarget?: try { -- guard case .loadNewTarget(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 175) -- }() -- case .print?: try { -- guard case .print(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 176) -- }() -- case .explore?: try { -- guard case .explore(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 177) -- }() -- case .probe?: try { -- guard case .probe(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 178) -- }() -- case .fixup?: try { -- guard case .fixup(let v)? = self.operation else { preconditionFailure() } -- try visitor.visitSingularMessageField(value: v, fieldNumber: 179) -- }() -- case nil: break -+ try withExtendedLifetime(_storage) { (_storage: _StorageClass) in -+ if !_storage._inouts.isEmpty { -+ try visitor.visitPackedUInt32Field(value: _storage._inouts, fieldNumber: 1) -+ } -+ switch _storage._operation { -+ case .opIdx(let v)?: -+ try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) -+ case .nop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 3) -+ case .loadInteger(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 4) -+ case .loadBigInt(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 5) -+ case .loadFloat(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 6) -+ case .loadString(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 7) -+ case .loadBoolean(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 8) -+ case .loadUndefined(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 9) -+ case .loadNull(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 10) -+ case .loadThis(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 11) -+ case .loadArguments(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 12) -+ case .loadRegExp(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 13) -+ case .beginObjectLiteral(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 14) -+ case .objectLiteralAddProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 15) -+ case .objectLiteralAddElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 16) -+ case .objectLiteralAddComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 17) -+ case .objectLiteralCopyProperties(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 18) -+ case .objectLiteralSetPrototype(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 19) -+ case .beginObjectLiteralMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 20) -+ case .endObjectLiteralMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 21) -+ case .beginObjectLiteralComputedMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 22) -+ case .endObjectLiteralComputedMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 23) -+ case .beginObjectLiteralGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 24) -+ case .endObjectLiteralGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 25) -+ case .beginObjectLiteralSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 26) -+ case .endObjectLiteralSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 27) -+ case .endObjectLiteral(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 28) -+ case .beginClassDefinition(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 29) -+ case .beginClassConstructor(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 30) -+ case .endClassConstructor(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 31) -+ case .classAddInstanceProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 32) -+ case .classAddInstanceElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 33) -+ case .classAddInstanceComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 34) -+ case .beginClassInstanceMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 35) -+ case .endClassInstanceMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 36) -+ case .beginClassInstanceGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 37) -+ case .endClassInstanceGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 38) -+ case .beginClassInstanceSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 39) -+ case .endClassInstanceSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 40) -+ case .classAddStaticProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 41) -+ case .classAddStaticElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 42) -+ case .classAddStaticComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 43) -+ case .beginClassStaticInitializer(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 44) -+ case .endClassStaticInitializer(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 45) -+ case .beginClassStaticMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 46) -+ case .endClassStaticMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 47) -+ case .beginClassStaticGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 48) -+ case .endClassStaticGetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 49) -+ case .beginClassStaticSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 50) -+ case .endClassStaticSetter(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 51) -+ case .classAddPrivateInstanceProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 52) -+ case .beginClassPrivateInstanceMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 53) -+ case .endClassPrivateInstanceMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 54) -+ case .classAddPrivateStaticProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 55) -+ case .beginClassPrivateStaticMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 56) -+ case .endClassPrivateStaticMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 57) -+ case .endClassDefinition(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 58) -+ case .createArray(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 59) -+ case .createIntArray(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 60) -+ case .createFloatArray(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 61) -+ case .createArrayWithSpread(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 62) -+ case .createTemplateString(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 63) -+ case .loadBuiltin(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 64) -+ case .getProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 65) -+ case .setProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 66) -+ case .updateProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 67) -+ case .deleteProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 68) -+ case .configureProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 69) -+ case .getElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 70) -+ case .setElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 71) -+ case .updateElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 72) -+ case .deleteElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 73) -+ case .configureElement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 74) -+ case .getComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 75) -+ case .setComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 76) -+ case .updateComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 77) -+ case .deleteComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 78) -+ case .configureComputedProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 79) -+ case .typeOf(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 80) -+ case .testInstanceOf(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 81) -+ case .testIn(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 82) -+ case .beginPlainFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 83) -+ case .endPlainFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 84) -+ case .beginArrowFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 85) -+ case .endArrowFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 86) -+ case .beginGeneratorFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 87) -+ case .endGeneratorFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 88) -+ case .beginAsyncFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 89) -+ case .endAsyncFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 90) -+ case .beginAsyncArrowFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 91) -+ case .endAsyncArrowFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 92) -+ case .beginAsyncGeneratorFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 93) -+ case .endAsyncGeneratorFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 94) -+ case .beginConstructor(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 95) -+ case .endConstructor(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 96) -+ case .return(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 97) -+ case .yield(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 98) -+ case .yieldEach(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 99) -+ case .await(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 100) -+ case .callFunction(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 101) -+ case .callFunctionWithSpread(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 102) -+ case .construct(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 103) -+ case .constructWithSpread(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 104) -+ case .callMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 105) -+ case .callMethodWithSpread(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 106) -+ case .callComputedMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 107) -+ case .callComputedMethodWithSpread(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 108) -+ case .unaryOperation(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 109) -+ case .binaryOperation(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 110) -+ case .ternaryOperation(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 111) -+ case .update(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 112) -+ case .dup(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 113) -+ case .reassign(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 114) -+ case .destructArray(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 115) -+ case .destructArrayAndReassign(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 116) -+ case .destructObject(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 117) -+ case .destructObjectAndReassign(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 118) -+ case .compare(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 119) -+ case .loadNamedVariable(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 120) -+ case .storeNamedVariable(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 121) -+ case .defineNamedVariable(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 122) -+ case .eval(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 123) -+ case .beginWith(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 124) -+ case .endWith(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 125) -+ case .callSuperConstructor(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 126) -+ case .callSuperMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 127) -+ case .getPrivateProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 128) -+ case .setPrivateProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 129) -+ case .updatePrivateProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 130) -+ case .callPrivateMethod(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 131) -+ case .getSuperProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 132) -+ case .setSuperProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 133) -+ case .getComputedSuperProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 134) -+ case .setComputedSuperProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 135) -+ case .updateSuperProperty(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 136) -+ case .beginIf(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 137) -+ case .beginElse(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 138) -+ case .endIf(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 139) -+ case .beginWhileLoopHeader(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 140) -+ case .beginWhileLoopBody(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 141) -+ case .endWhileLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 142) -+ case .beginDoWhileLoopBody(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 143) -+ case .beginDoWhileLoopHeader(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 144) -+ case .endDoWhileLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 145) -+ case .beginForLoopInitializer(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 146) -+ case .beginForLoopCondition(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 147) -+ case .beginForLoopAfterthought(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 148) -+ case .beginForLoopBody(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 149) -+ case .endForLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 150) -+ case .beginForInLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 151) -+ case .endForInLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 152) -+ case .beginForOfLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 153) -+ case .beginForOfLoopWithDestruct(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 154) -+ case .endForOfLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 155) -+ case .beginRepeatLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 156) -+ case .endRepeatLoop(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 157) -+ case .loopBreak(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 158) -+ case .loopContinue(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 159) -+ case .beginTry(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 160) -+ case .beginCatch(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 161) -+ case .beginFinally(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 162) -+ case .endTryCatchFinally(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 163) -+ case .throwException(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 164) -+ case .beginCodeString(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 165) -+ case .endCodeString(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 166) -+ case .beginBlockStatement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 167) -+ case .endBlockStatement(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 168) -+ case .beginSwitch(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 169) -+ case .beginSwitchCase(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 170) -+ case .beginSwitchDefaultCase(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 171) -+ case .endSwitchCase(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 172) -+ case .endSwitch(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 173) -+ case .switchBreak(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 174) -+ case .loadNewTarget(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 175) -+ case .print(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 176) -+ case .explore(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 177) -+ case .probe(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 178) -+ case .fixup(let v)?: -+ try visitor.visitSingularMessageField(value: v, fieldNumber: 179) -+ case nil: break -+ } - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_Instruction, rhs: Fuzzilli_Protobuf_Instruction) -> Bool { -- if lhs.inouts != rhs.inouts {return false} -- if lhs.operation != rhs.operation {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._inouts != rhs_storage._inouts {return false} -+ if _storage._operation != rhs_storage._operation {return false} -+ return true -+ } -+ if !storagesAreEqual {return false} -+ } - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -@@ -5676,7 +3924,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa - ] - - fileprivate class _StorageClass { -- var _uuid: Data = Data() -+ var _uuid: Data = SwiftProtobuf.Internal.emptyData - var _code: [Fuzzilli_Protobuf_Instruction] = [] - var _comments: Dictionary = [:] - var _parent: Fuzzilli_Protobuf_Program? = nil -@@ -5704,14 +3952,11 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa - _ = _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.decodeSingularBytesField(value: &_storage._uuid) }() -- 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 1: try decoder.decodeSingularBytesField(value: &_storage._uuid) -+ case 2: try decoder.decodeRepeatedMessageField(value: &_storage._code) -+ case 3: try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap.self, value: &_storage._comments) -+ case 4: try decoder.decodeSingularMessageField(value: &_storage._parent) - default: break - } - } -@@ -5720,10 +3965,6 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa - - public func traverse(visitor: inout V) throws { - 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._uuid.isEmpty { - try visitor.visitSingularBytesField(value: _storage._uuid, fieldNumber: 1) - } -@@ -5733,9 +3974,9 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa - if !_storage._comments.isEmpty { - try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMap.self, value: _storage._comments, fieldNumber: 3) - } -- try { if let v = _storage._parent { -+ if let v = _storage._parent { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) -- } }() -+ } - } - try unknownFields.traverse(visitor: &visitor) - } -diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto -index 515dce6..c8da3a3 100644 ---- a/Sources/Fuzzilli/Protobuf/program.proto -+++ b/Sources/Fuzzilli/Protobuf/program.proto -@@ -1,4 +1,4 @@ --// Copyright 2023 Google LLC -+// Copyright 2024 Google LLC - // - // Licensed under the Apache License, Version 2.0 (the "License"); - // you may not use this file except in compliance with the License. -diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift -index 909deec..92bf762 100644 ---- a/Sources/Fuzzilli/Protobuf/sync.pb.swift -+++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift -@@ -58,9 +58,9 @@ public struct Fuzzilli_Protobuf_FuzzerState { - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - -- public var corpus: Data = Data() -+ public var corpus: Data = SwiftProtobuf.Internal.emptyData - -- public var evaluatorState: Data = Data() -+ public var evaluatorState: Data = SwiftProtobuf.Internal.emptyData - - public var unknownFields = SwiftProtobuf.UnknownStorage() - -@@ -132,6 +132,11 @@ public struct Fuzzilli_Protobuf_Statistics { - set {_uniqueStorage()._avgExecutionTime = newValue} - } - -+ public var avgBugOracleTime: Double { -+ get {return _storage._avgBugOracleTime} -+ set {_uniqueStorage()._avgBugOracleTime = newValue} -+ } -+ - //// The current number of executions per second. - public var execsPerSecond: Double { - get {return _storage._execsPerSecond} -@@ -174,6 +179,46 @@ public struct Fuzzilli_Protobuf_Statistics { - set {_uniqueStorage()._timeoutRate = newValue} - } - -+ public var differentialSamples: UInt64 { -+ get {return _storage._differentialSamples} -+ set {_uniqueStorage()._differentialSamples = newValue} -+ } -+ -+ public var turbofanSamples: UInt64 { -+ get {return _storage._turbofanSamples} -+ set {_uniqueStorage()._turbofanSamples = newValue} -+ } -+ -+ public var maglevSamples: UInt64 { -+ get {return _storage._maglevSamples} -+ set {_uniqueStorage()._maglevSamples = newValue} -+ } -+ -+ public var sparkplugSamples: UInt64 { -+ get {return _storage._sparkplugSamples} -+ set {_uniqueStorage()._sparkplugSamples = newValue} -+ } -+ -+ public var relationsPerformed: UInt64 { -+ get {return _storage._relationsPerformed} -+ set {_uniqueStorage()._relationsPerformed = newValue} -+ } -+ -+ public var jitSamples: UInt64 { -+ get {return _storage._jitSamples} -+ set {_uniqueStorage()._jitSamples = newValue} -+ } -+ -+ public var avgDumpSizeOpt: Double { -+ get {return _storage._avgDumpSizeOpt} -+ set {_uniqueStorage()._avgDumpSizeOpt = newValue} -+ } -+ -+ public var avgDumpSizeUnOpt: Double { -+ get {return _storage._avgDumpSizeUnOpt} -+ set {_uniqueStorage()._avgDumpSizeUnOpt = newValue} -+ } -+ - public var unknownFields = SwiftProtobuf.UnknownStorage() - - public init() {} -@@ -181,12 +226,6 @@ public struct Fuzzilli_Protobuf_Statistics { - fileprivate var _storage = _StorageClass.defaultInstance - } - --#if swift(>=5.5) && canImport(_Concurrency) --extension Fuzzilli_Protobuf_LogMessage: @unchecked Sendable {} --extension Fuzzilli_Protobuf_FuzzerState: @unchecked Sendable {} --extension Fuzzilli_Protobuf_Statistics: @unchecked Sendable {} --#endif // swift(>=5.5) && canImport(_Concurrency) -- - // MARK: - Code below here is support for the SwiftProtobuf runtime. - - fileprivate let _protobuf_package = "fuzzilli.protobuf" -@@ -202,14 +241,11 @@ extension Fuzzilli_Protobuf_LogMessage: SwiftProtobuf.Message, SwiftProtobuf._Me - - 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.origin) }() -- case 2: try { try decoder.decodeSingularUInt32Field(value: &self.level) }() -- case 3: try { try decoder.decodeSingularStringField(value: &self.label) }() -- case 4: try { try decoder.decodeSingularStringField(value: &self.content) }() -+ case 1: try decoder.decodeSingularStringField(value: &self.origin) -+ case 2: try decoder.decodeSingularUInt32Field(value: &self.level) -+ case 3: try decoder.decodeSingularStringField(value: &self.label) -+ case 4: try decoder.decodeSingularStringField(value: &self.content) - default: break - } - } -@@ -250,12 +286,9 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M - - 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.decodeSingularBytesField(value: &self.corpus) }() -- case 2: try { try decoder.decodeSingularBytesField(value: &self.evaluatorState) }() -+ case 1: try decoder.decodeSingularBytesField(value: &self.corpus) -+ case 2: try decoder.decodeSingularBytesField(value: &self.evaluatorState) - default: break - } - } -@@ -299,6 +332,15 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - 15: .same(proto: "coverage"), - 16: .same(proto: "correctnessRate"), - 17: .same(proto: "timeoutRate"), -+ 18: .same(proto: "differentialSamples"), -+ 19: .same(proto: "turbofanSamples"), -+ 20: .same(proto: "maglevSamples"), -+ 21: .same(proto: "relationsPerformed"), -+ 22: .same(proto: "sparkplugSamples"), -+ 23: .same(proto: "avgBugOracleTime"), -+ 24: .same(proto: "jitSamples"), -+ 25: .same(proto: "avgDumpSizeOpt"), -+ 26: .same(proto: "avgDumpSizeUnOpt"), - ] - - fileprivate class _StorageClass { -@@ -319,6 +361,15 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - var _coverage: Double = 0 - var _correctnessRate: Double = 0 - var _timeoutRate: Double = 0 -+ var _differentialSamples: UInt64 = 0 -+ var _turbofanSamples: UInt64 = 0 -+ var _maglevSamples: UInt64 = 0 -+ var _relationsPerformed: UInt64 = 0 -+ var _sparkplugSamples: UInt64 = 0 -+ var _avgBugOracleTime: Double = 0 -+ var _jitSamples: UInt64 = 0 -+ var _avgDumpSizeOpt: Double = 0 -+ var _avgDumpSizeUnOpt: Double = 0 - - static let defaultInstance = _StorageClass() - -@@ -342,6 +393,15 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - _coverage = source._coverage - _correctnessRate = source._correctnessRate - _timeoutRate = source._timeoutRate -+ _differentialSamples = source._differentialSamples -+ _turbofanSamples = source._turbofanSamples -+ _maglevSamples = source._maglevSamples -+ _relationsPerformed = source._relationsPerformed -+ _sparkplugSamples = source._sparkplugSamples -+ _avgBugOracleTime = source._avgBugOracleTime -+ _jitSamples = source._jitSamples -+ _avgDumpSizeOpt = source._avgDumpSizeOpt -+ _avgDumpSizeUnOpt = source._avgDumpSizeUnOpt - } - } - -@@ -356,27 +416,33 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - _ = _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.decodeSingularUInt64Field(value: &_storage._totalSamples) }() -- case 2: try { try decoder.decodeSingularUInt64Field(value: &_storage._validSamples) }() -- case 3: try { try decoder.decodeSingularUInt64Field(value: &_storage._interestingSamples) }() -- case 4: try { try decoder.decodeSingularUInt64Field(value: &_storage._timedOutSamples) }() -- case 5: try { try decoder.decodeSingularUInt64Field(value: &_storage._crashingSamples) }() -- case 6: try { try decoder.decodeSingularUInt64Field(value: &_storage._totalExecs) }() -- case 7: try { try decoder.decodeSingularDoubleField(value: &_storage._avgCorpusSize) }() -- case 8: try { try decoder.decodeSingularDoubleField(value: &_storage._avgProgramSize) }() -- case 9: try { try decoder.decodeSingularDoubleField(value: &_storage._avgCorpusProgramSize) }() -- case 10: try { try decoder.decodeSingularDoubleField(value: &_storage._avgExecutionTime) }() -- case 11: try { try decoder.decodeSingularDoubleField(value: &_storage._execsPerSecond) }() -- case 12: try { try decoder.decodeSingularDoubleField(value: &_storage._fuzzerOverhead) }() -- case 13: try { try decoder.decodeSingularDoubleField(value: &_storage._minimizationOverhead) }() -- case 14: try { try decoder.decodeSingularUInt64Field(value: &_storage._numChildNodes) }() -- case 15: try { try decoder.decodeSingularDoubleField(value: &_storage._coverage) }() -- case 16: try { try decoder.decodeSingularDoubleField(value: &_storage._correctnessRate) }() -- case 17: try { try decoder.decodeSingularDoubleField(value: &_storage._timeoutRate) }() -+ case 1: try decoder.decodeSingularUInt64Field(value: &_storage._totalSamples) -+ case 2: try decoder.decodeSingularUInt64Field(value: &_storage._validSamples) -+ case 3: try decoder.decodeSingularUInt64Field(value: &_storage._interestingSamples) -+ case 4: try decoder.decodeSingularUInt64Field(value: &_storage._timedOutSamples) -+ case 5: try decoder.decodeSingularUInt64Field(value: &_storage._crashingSamples) -+ case 6: try decoder.decodeSingularUInt64Field(value: &_storage._totalExecs) -+ case 7: try decoder.decodeSingularDoubleField(value: &_storage._avgCorpusSize) -+ case 8: try decoder.decodeSingularDoubleField(value: &_storage._avgProgramSize) -+ case 9: try decoder.decodeSingularDoubleField(value: &_storage._avgCorpusProgramSize) -+ case 10: try decoder.decodeSingularDoubleField(value: &_storage._avgExecutionTime) -+ case 11: try decoder.decodeSingularDoubleField(value: &_storage._execsPerSecond) -+ case 12: try decoder.decodeSingularDoubleField(value: &_storage._fuzzerOverhead) -+ case 13: try decoder.decodeSingularDoubleField(value: &_storage._minimizationOverhead) -+ case 14: try decoder.decodeSingularUInt64Field(value: &_storage._numChildNodes) -+ case 15: try decoder.decodeSingularDoubleField(value: &_storage._coverage) -+ case 16: try decoder.decodeSingularDoubleField(value: &_storage._correctnessRate) -+ case 17: try decoder.decodeSingularDoubleField(value: &_storage._timeoutRate) -+ case 18: try decoder.decodeSingularUInt64Field(value: &_storage._differentialSamples) -+ case 19: try decoder.decodeSingularUInt64Field(value: &_storage._turbofanSamples) -+ case 20: try decoder.decodeSingularUInt64Field(value: &_storage._maglevSamples) -+ case 21: try decoder.decodeSingularUInt64Field(value: &_storage._relationsPerformed) -+ case 22: try decoder.decodeSingularUInt64Field(value: &_storage._sparkplugSamples) -+ case 23: try decoder.decodeSingularDoubleField(value: &_storage._avgBugOracleTime) -+ case 24: try decoder.decodeSingularUInt64Field(value: &_storage._jitSamples) -+ case 25: try decoder.decodeSingularDoubleField(value: &_storage._avgDumpSizeOpt) -+ case 26: try decoder.decodeSingularDoubleField(value: &_storage._avgDumpSizeUnOpt) - default: break - } - } -@@ -436,6 +502,33 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - if _storage._timeoutRate != 0 { - try visitor.visitSingularDoubleField(value: _storage._timeoutRate, fieldNumber: 17) - } -+ if _storage._differentialSamples != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._differentialSamples, fieldNumber: 18) -+ } -+ if _storage._turbofanSamples != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._turbofanSamples, fieldNumber: 19) -+ } -+ if _storage._maglevSamples != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._maglevSamples, fieldNumber: 20) -+ } -+ if _storage._relationsPerformed != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._relationsPerformed, fieldNumber: 21) -+ } -+ if _storage._sparkplugSamples != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._sparkplugSamples, fieldNumber: 22) -+ } -+ if _storage._avgBugOracleTime != 0 { -+ try visitor.visitSingularDoubleField(value: _storage._avgBugOracleTime, fieldNumber: 23) -+ } -+ if _storage._jitSamples != 0 { -+ try visitor.visitSingularUInt64Field(value: _storage._jitSamples, fieldNumber: 24) -+ } -+ if _storage._avgDumpSizeOpt != 0 { -+ try visitor.visitSingularDoubleField(value: _storage._avgDumpSizeOpt, fieldNumber: 25) -+ } -+ if _storage._avgDumpSizeUnOpt != 0 { -+ try visitor.visitSingularDoubleField(value: _storage._avgDumpSizeUnOpt, fieldNumber: 26) -+ } - } - try unknownFields.traverse(visitor: &visitor) - } -@@ -462,6 +555,15 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me - if _storage._coverage != rhs_storage._coverage {return false} - if _storage._correctnessRate != rhs_storage._correctnessRate {return false} - if _storage._timeoutRate != rhs_storage._timeoutRate {return false} -+ if _storage._differentialSamples != rhs_storage._differentialSamples {return false} -+ if _storage._turbofanSamples != rhs_storage._turbofanSamples {return false} -+ if _storage._maglevSamples != rhs_storage._maglevSamples {return false} -+ if _storage._relationsPerformed != rhs_storage._relationsPerformed {return false} -+ if _storage._sparkplugSamples != rhs_storage._sparkplugSamples {return false} -+ if _storage._avgBugOracleTime != rhs_storage._avgBugOracleTime {return false} -+ if _storage._jitSamples != rhs_storage._jitSamples {return false} -+ if _storage._avgDumpSizeOpt != rhs_storage._avgDumpSizeOpt {return false} -+ if _storage._avgDumpSizeUnOpt != rhs_storage._avgDumpSizeUnOpt {return false} - return true - } - if !storagesAreEqual {return false} -diff --git a/Sources/Fuzzilli/Protobuf/sync.proto b/Sources/Fuzzilli/Protobuf/sync.proto -index f237d82..bb1942b 100644 ---- a/Sources/Fuzzilli/Protobuf/sync.proto -+++ b/Sources/Fuzzilli/Protobuf/sync.proto -@@ -81,4 +81,22 @@ message Statistics { - - /// The timeout rate of recently generated programs (number of timeouts divided by number of generated programs). - double timeoutRate = 17; -+ -+ uint64 differentialSamples = 18; -+ -+ uint64 turbofanSamples = 19; -+ -+ uint64 maglevSamples = 20; -+ -+ uint64 relationsPerformed = 21; -+ -+ uint64 sparkplugSamples = 22; -+ -+ double avgBugOracleTime = 23; -+ -+ uint64 jitSamples = 24; -+ -+ double avgDumpSizeOpt = 25; -+ -+ double avgDumpSizeUnOpt = 26; - } -diff --git a/Sources/Fuzzilli/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift -index be921c9..665b8e9 100644 ---- a/Sources/Fuzzilli/Util/MockFuzzer.swift -+++ b/Sources/Fuzzilli/Util/MockFuzzer.swift -@@ -17,22 +17,31 @@ import Foundation - // Mock implementations of fuzzer components for testing. - - struct MockExecution: Execution { -- let outcome: ExecutionOutcome -+ var outcome: ExecutionOutcome - let stdout: String - let stderr: String - let fuzzout: String -- let execTime: TimeInterval -+ var execTime: TimeInterval -+ let executionHash: Int -+ var compilersUsed: [JITType] -+ var unOptStdout: String?=nil -+ var optStdout: String?=nil -+ var reproducesInNonReplMode: Bool?=false -+ var bugOracleTime: TimeInterval?=nil - } - - class MockScriptRunner: ScriptRunner { - var processArguments: [String] = [] - -- func run(_ script: String, withTimeout timeout: UInt32) -> Execution { -+ func run(_ script: String, withTimeout timeout: UInt32, -+ differentialFuzzingPositionDumpSeed: UInt32) -> Execution { - return MockExecution(outcome: .succeeded, - stdout: "", - stderr: "", - fuzzout: "", -- execTime: TimeInterval(0.1)) -+ execTime: TimeInterval(0.1), -+ executionHash: 0, -+ compilersUsed: []) - } - - func setEnvironmentVariable(_ key: String, to value: String) {} -@@ -162,6 +171,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi - - // A script runner to execute JavaScript code in an instrumented JS engine. - let runner = maybeRunner ?? MockScriptRunner() -+ let referenceRunner = maybeRunner ?? MockScriptRunner() - - // the mutators to use for this fuzzing engine. - let mutators = WeightedList([ -@@ -197,6 +207,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi - // Construct the fuzzer instance. - let fuzzer = Fuzzer(configuration: configuration, - scriptRunner: runner, -+ referenceRunner: referenceRunner, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, -@@ -206,6 +217,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi - lifter: lifter, - corpus: corpus, - minimizer: minimizer, -+ localId: 0, - queue: DispatchQueue.main) - - fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in -diff --git a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift b/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift -index 8d38b9b..bcba056 100644 ---- a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift -@@ -19,6 +19,8 @@ let duktapeProfile = Profile( - ["--reprl"] - }, - -+ processArgsReference: ["--reprl"], -+ - processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -26,6 +28,7 @@ let duktapeProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = () => null; - """, - - codeSuffix: """ -@@ -35,6 +38,10 @@ let duktapeProfile = Profile( - - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)"], - -+ differentialTests: [], -+ -+ differentialTestsInvariant: [], -+ - additionalCodeGenerators: [], - - additionalProgramTemplates: WeightedList([]), -diff --git a/Sources/FuzzilliCli/Profiles/JSCProfile.swift b/Sources/FuzzilliCli/Profiles/JSCProfile.swift -index ee6a2f3..11c29b1 100644 ---- a/Sources/FuzzilliCli/Profiles/JSCProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/JSCProfile.swift -@@ -36,10 +36,14 @@ fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in - b.callFunction(b.loadBuiltin("gc")) - } - -+fileprivate let commonArgs = [ -+ "--validateOptions=true", -+ "--reprl", -+] -+ - let jscProfile = Profile( - processArgs: { randomize in -- var args = [ -- "--validateOptions=true", -+ var args = commonArgs + [ - // No need to call functions thousands of times before they are JIT compiled - "--thresholdForJITSoon=10", - "--thresholdForJITAfterWarmUp=10", -@@ -49,8 +53,7 @@ let jscProfile = Profile( - "--thresholdForFTLOptimizeAfterWarmUp=1000", - "--thresholdForFTLOptimizeSoon=1000", - // Enable bounds check elimination validation -- "--validateBCE=true", -- "--reprl"] -+ "--validateBCE=true"] - - guard randomize else { return args } - -@@ -69,6 +72,13 @@ let jscProfile = Profile( - return args - }, - -+ processArgsReference: commonArgs + [ -+ "--useConcurrentGC=false", -+ // Disable JIT -+ "--useFTLJIT=false", -+ "--useBaselineJIT=false", -+ "--useDFGJIT=false"], -+ - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -76,6 +86,7 @@ let jscProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = fuzzilli_hash; - """, - - codeSuffix: """ -@@ -84,7 +95,14 @@ let jscProfile = Profile( - - ecmaVersion: ECMAScriptVersion.es6, - -- crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"], -+ crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", -+ "fuzzilli('FUZZILLI_CRASH', 1)", -+ "fuzzilli('FUZZILLI_CRASH', 2)"], -+ -+ differentialTests: ["fuzzilli_hash(fuzzilli('FUZZILLI_RANDOM'))",], -+ -+ differentialTestsInvariant: ["fuzzilli_hash(Math.random())", -+ "fuzzilli_hash(Date.now())",], - - additionalCodeGenerators: [ - (ForceDFGCompilationGenerator, 5), -diff --git a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift b/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift -index 3a41c64..cc069b1 100644 ---- a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift -@@ -19,6 +19,8 @@ let jerryscriptProfile = Profile( - ["--reprl-fuzzilli"] - }, - -+ processArgsReference: ["--reprl-fuzzilli"], -+ - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -26,6 +28,7 @@ let jerryscriptProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = () => null; - """, - - codeSuffix: """ -@@ -35,6 +38,10 @@ let jerryscriptProfile = Profile( - - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)"], - -+ differentialTests: [], -+ -+ differentialTestsInvariant: [], -+ - additionalCodeGenerators: [], - - additionalProgramTemplates: WeightedList([]), -diff --git a/Sources/FuzzilliCli/Profiles/Profile.swift b/Sources/FuzzilliCli/Profiles/Profile.swift -index 1a02a6d..dcd37d2 100644 ---- a/Sources/FuzzilliCli/Profiles/Profile.swift -+++ b/Sources/FuzzilliCli/Profiles/Profile.swift -@@ -14,8 +14,9 @@ - - import Fuzzilli - --struct Profile { -+public struct Profile { - let processArgs: (_ randomize: Bool) -> [String] -+ let processArgsReference: [String] - let processEnv: [String : String] - let maxExecsBeforeRespawn: Int - // Timeout is in milliseconds. -@@ -28,6 +29,9 @@ struct Profile { - // Used to verify that crashes can be detected. - let crashTests: [String] - -+ let differentialTests: [String] -+ let differentialTestsInvariant: [String] -+ - let additionalCodeGenerators: [(CodeGenerator, Int)] - let additionalProgramTemplates: WeightedList - -@@ -40,7 +44,7 @@ struct Profile { - let optionalPostProcessor: FuzzingPostProcessor? - } - --let profiles = [ -+public let profiles = [ - "qtjs": qtjsProfile, - "qjs": qjsProfile, - "jsc": jscProfile, -@@ -49,5 +53,4 @@ let profiles = [ - "duktape": duktapeProfile, - "jerryscript": jerryscriptProfile, - "xs": xsProfile, -- "v8holefuzzing": v8HoleFuzzingProfile, - ] -diff --git a/Sources/FuzzilliCli/Profiles/QjsProfile.swift b/Sources/FuzzilliCli/Profiles/QjsProfile.swift -index 90bcbf3..68f4ebd 100644 ---- a/Sources/FuzzilliCli/Profiles/QjsProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/QjsProfile.swift -@@ -19,6 +19,8 @@ let qjsProfile = Profile( - ["--reprl"] - }, - -+ processArgsReference: ["--reprl"], -+ - processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -26,6 +28,7 @@ let qjsProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = () => null; - """, - - codeSuffix: """ -@@ -35,6 +38,11 @@ let qjsProfile = Profile( - - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"], - -+ differentialTests: [], -+ -+ differentialTestsInvariant: [], -+ -+ - additionalCodeGenerators: [], - - additionalProgramTemplates: WeightedList([]), -diff --git a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift b/Sources/FuzzilliCli/Profiles/QtjsProfile.swift -index 7595516..3ba7fc4 100644 ---- a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/QtjsProfile.swift -@@ -27,6 +27,8 @@ let qtjsProfile = Profile( - ["-reprl"] - }, - -+ processArgsReference: ["-reprl"], -+ - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -34,6 +36,7 @@ let qtjsProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = () => null; - """, - - codeSuffix: """ -@@ -45,6 +48,10 @@ let qtjsProfile = Profile( - // Used to verify that crashes can be detected. - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)"], - -+ differentialTests: [], -+ -+ differentialTestsInvariant: [], -+ - additionalCodeGenerators: [ - (ForceQV4JITGenerator, 20), - ], -@@ -57,6 +64,7 @@ let qtjsProfile = Profile( - - additionalBuiltins: [ - "gc" : .function([] => .undefined), -+ "placeholder" : .function([] => .undefined), - ], - - optionalPostProcessor: nil -diff --git a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift b/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift -index 081cbd3..4d7aced 100644 ---- a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift -@@ -27,16 +27,25 @@ fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in - b.callFunction(b.loadBuiltin("gc")) - } - -+fileprivate let commonArgs = [ -+ "--baseline-warmup-threshold=10", -+ "--fuzzing-safe", -+ "--disable-oom-functions", -+ "--reprl" -+] -+ -+fileprivate let differentialArgs = [ -+ "--differential-testing" -+] -+ - let spidermonkeyProfile = Profile( - processArgs: { randomize in -- var args = [ -- "--baseline-warmup-threshold=10", -+ var args = commonArgs + [ - "--ion-warmup-threshold=100", - "--ion-check-range-analysis", - "--ion-extra-checks", -- "--fuzzing-safe", -- "--disable-oom-functions", -- "--reprl"] -+ ] -+ - - guard randomize else { return args } - -@@ -70,6 +79,11 @@ let spidermonkeyProfile = Profile( - return args - }, - -+ processArgsReference: commonArgs + differentialArgs + [ -+ "--no-threads", -+ "--no-ion", -+ ], -+ - processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -77,6 +91,7 @@ let spidermonkeyProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = fuzzilli_hash; - """, - - codeSuffix: """ -@@ -85,7 +100,14 @@ let spidermonkeyProfile = Profile( - - ecmaVersion: ECMAScriptVersion.es6, - -- crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"], -+ crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", -+ "fuzzilli('FUZZILLI_CRASH', 1)", -+ "fuzzilli('FUZZILLI_CRASH', 2)"], -+ -+ differentialTests: ["for(let i=0; i<200; i++) {fuzzilli_hash(fuzzilli('FUZZILLI_RANDOM'))}",], -+ -+ differentialTestsInvariant: ["for(let i=0; i < 200; i++) {fuzzilli_hash(Math.random())}", -+ "for(let i=0; i < 200; i++) {fuzzilli_hash(Date.now())}",], - - additionalCodeGenerators: [ - (ForceSpidermonkeyIonGenerator, 10), -diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift -deleted file mode 100644 -index 1fcf1e3..0000000 ---- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift -+++ /dev/null -@@ -1,106 +0,0 @@ --// Copyright 2023 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 Fuzzilli -- --// TODO: move common parts (e.g. generators) into a V8CommonProfile.swift. --fileprivate let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITCompilationThroughLoopGenerator", 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.callFunction(f, withArgs: arguments) -- } --} --fileprivate let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in -- assert(b.type(of: f).Is(.function())) -- let arguments = b.randomArguments(forCalling: f) -- b.callFunction(f, withArgs: arguments) -- b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); -- b.callFunction(f, withArgs: arguments) -- b.callFunction(f, withArgs: arguments) -- b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); -- b.callFunction(f, withArgs: arguments) --} --fileprivate let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in -- assert(b.type(of: f).Is(.function())) -- let arguments = b.randomArguments(forCalling: f) -- b.callFunction(f, withArgs: arguments) -- b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); -- b.callFunction(f, withArgs: arguments) -- b.callFunction(f, withArgs: arguments) -- b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); -- b.callFunction(f, withArgs: arguments) --} --// Insert random GC calls throughout our code. --fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in -- let gc = b.loadBuiltin("gc") -- // Do minor GCs more frequently. -- let type = b.loadString(probability(0.25) ? "major" : "minor") -- // If the execution type is 'async', gc() returns a Promise, we currently -- // do not really handle other than typing the 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. -- let execution = b.loadString(probability(0.5) ? "sync" : "async") -- b.callFunction(gc, withArgs: [b.createObject(with: ["type": type, "execution": execution])]) --} -- --// 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 = ValueGenerator("HoleLeakGenerator") { b, args in -- b.eval("%LeakHole()", hasOutput: true) --} -- --let v8HoleFuzzingProfile = Profile( -- processArgs: { randomize in -- var args = [ -- "--expose-gc", -- "--omit-quit", -- "--allow-natives-syntax", -- "--fuzzing", -- "--hole-fuzzing", -- "--jit-fuzzing", -- "--future", -- "--harmony", -- ] -- return args -- }, -- processEnv: [:], -- maxExecsBeforeRespawn: 1000, -- timeout: 250, -- codePrefix: """ -- """, -- codeSuffix: """ -- """, -- ecmaVersion: ECMAScriptVersion.es6, -- crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 7)"], -- additionalCodeGenerators: [ -- (ForceJITCompilationThroughLoopGenerator, 5), -- (ForceTurboFanCompilationGenerator, 5), -- (ForceMaglevCompilationGenerator, 5), -- (GcGenerator, 10), -- (HoleLeakGenerator, 25), -- ], -- additionalProgramTemplates: WeightedList([ -- ]), -- disabledCodeGenerators: [], -- disabledMutators: [], -- additionalBuiltins: [ -- "gc" : .function([] => (.undefined | .jsPromise)), -- "d8" : .object(), -- "Worker" : .constructor([.anything, .object()] => .object(withMethods: ["postMessage","getMessage"])), -- ], -- optionalPostProcessor: nil --) -diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift -index 6325b44..ae32f8e 100644 ---- a/Sources/FuzzilliCli/Profiles/V8Profile.swift -+++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift -@@ -411,131 +411,16 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in - b.build(n: 15) - } - --let v8Profile = Profile( -- processArgs: { randomize in -- var args = [ -- "--expose-gc", -- "--omit-quit", -- "--allow-natives-syntax", -- "--fuzzing", -- "--jit-fuzzing", -- "--future", -- "--harmony", -- "--js-staging" -- ] -- -- guard randomize else { return args } -- -- // -- // Existing features that should sometimes be disabled. -- // -- if probability(0.1) { -- args.append("--no-turbofan") -- } -- -- if probability(0.1) { -- args.append("--no-turboshaft") -- } -- -- if probability(0.1) { -- args.append("--no-maglev") -- } -- -- if probability(0.1) { -- args.append("--no-sparkplug") -- } -- -- if probability(0.1) { -- args.append("--no-short-builtin-calls") -- } -- -- // -- // Future features that should sometimes be enabled. -- // -- if probability(0.25) { -- args.append("--minor-ms") -- } -- -- if probability(0.25) { -- args.append("--shared-string-table") -- } -- -- if probability(0.25) && !args.contains("--no-maglev") { -- args.append("--maglev-future") -- } -- -- if probability(0.25) && !args.contains("--no-turboshaft") { -- args.append("--turboshaft-future") -- } -+fileprivate let config = V8DifferentialConfig() - -- if probability(0.1) && !args.contains("--no-turboshaft") { -- args.append("--turboshaft-typed-optimizations") -- } -- -- if probability(0.1) { -- args.append("--harmony-struct") -- } -- -- // -- // Sometimes enable additional verification/stressing logic (which may be fairly expensive). -- // -- if probability(0.1) { -- args.append("--verify-heap") -- } -- if probability(0.1) { -- args.append("--turbo-verify") -- } -- if probability(0.1) { -- args.append("--turbo-verify-allocation") -- } -- if probability(0.1) { -- args.append("--assert-types") -- } -- if probability(0.1) { -- args.append("--turboshaft-assert-types") -- } -- if probability(0.1) { -- args.append("--deopt-every-n-times=\(chooseUniform(from: [100, 250, 500, 1000, 2500, 5000, 10000]))") -- } -- -- // -- // More exotic configuration changes. -- // -- if probability(0.05) { -- if probability(0.5) { args.append("--stress-gc-during-compilation") } -- if probability(0.5) { args.append("--lazy-new-space-shrinking") } -- -- args.append(probability(0.5) ? "--always-sparkplug" : "--no-always-sparkplug") -- args.append(probability(0.5) ? "--always-osr" : "--no-always-osr") -- args.append(probability(0.5) ? "--concurrent-osr" : "--no-concurrent-osr") -- args.append(probability(0.5) ? "--force-slow-path" : "--no-force-slow-path") -- -- // Maglev related flags -- args.append(probability(0.5) ? "--maglev-inline-api-calls" : "--no-maglev-inline-api-calls") -- -- // Compiler related flags -- args.append(probability(0.5) ? "--always-turbofan" : "--no-always-turbofan") -- args.append(probability(0.5) ? "--turbo-move-optimization" : "--no-turbo-move-optimization") -- args.append(probability(0.5) ? "--turbo-jt" : "--no-turbo-jt") -- args.append(probability(0.5) ? "--turbo-loop-peeling" : "--no-turbo-loop-peeling") -- args.append(probability(0.5) ? "--turbo-loop-variable" : "--no-turbo-loop-variable") -- args.append(probability(0.5) ? "--turbo-loop-rotation" : "--no-turbo-loop-rotation") -- args.append(probability(0.5) ? "--turbo-cf-optimization" : "--no-turbo-cf-optimization") -- args.append(probability(0.5) ? "--turbo-escape" : "--no-turbo-escape") -- args.append(probability(0.5) ? "--turbo-allocation-folding" : "--no-turbo-allocation-folding") -- args.append(probability(0.5) ? "--turbo-instruction-scheduling" : "--no-turbo-instruction-scheduling") -- args.append(probability(0.5) ? "--turbo-stress-instruction-scheduling" : "--no-turbo-stress-instruction-scheduling") -- args.append(probability(0.5) ? "--turbo-store-elimination" : "--no-turbo-store-elimination") -- args.append(probability(0.5) ? "--turbo-rewrite-far-jumps" : "--no-turbo-rewrite-far-jumps") -- args.append(probability(0.5) ? "--turbo-optimize-apply" : "--no-turbo-optimize-apply") -- 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(probability(0.5) ? "--turbo-load-elimination" : "--no-turbo-load-elimination") -- args.append(probability(0.5) ? "--turbo-inlining" : "--no-turbo-inlining") -- args.append(probability(0.5) ? "--turbo-splitting" : "--no-turbo-splitting") -- } -+let v8Profile = Profile( -+ processArgs: { _ in -+ var args = config.commonArgs -+ args.append(contentsOf: config.differentialArgs) -+ return args -+ }, - -- return args -- }, -+ processArgsReference: config.commonArgs + config.referenceArgs, - - processEnv: [:], - -@@ -543,8 +428,9 @@ let v8Profile = Profile( - - timeout: 250, - -- codePrefix: """ -- """, -+ codePrefix: """ -+%EnableFrameDumping(); -+""", - - codeSuffix: """ - """, -@@ -553,6 +439,10 @@ let v8Profile = Profile( - - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)", "fuzzilli('FUZZILLI_CRASH', 3)"], - -+ differentialTests: [], -+ -+ differentialTestsInvariant: [], -+ - additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), -diff --git a/Sources/FuzzilliCli/Profiles/XSProfile.swift b/Sources/FuzzilliCli/Profiles/XSProfile.swift -index 422ecc4..55a6239 100644 ---- a/Sources/FuzzilliCli/Profiles/XSProfile.swift -+++ b/Sources/FuzzilliCli/Profiles/XSProfile.swift -@@ -19,6 +19,8 @@ let xsProfile = Profile( - ["-f"] - }, - -+ processArgsReference: ["-f"], -+ - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], - - maxExecsBeforeRespawn: 1000, -@@ -26,6 +28,7 @@ let xsProfile = Profile( - timeout: 250, - - codePrefix: """ -+ const fhash = () => null; - """, - - codeSuffix: """ -@@ -36,6 +39,11 @@ let xsProfile = Profile( - - crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"], - -+ differentialTests: ["fuzzilli_hash(fuzzilli('FUZZILLI_RANDOM'))",], -+ -+ differentialTestsInvariant: ["fuzzilli_hash(Math.random())", -+ "fuzzilli_hash(Date.now())",], -+ - additionalCodeGenerators: [], - - additionalProgramTemplates: WeightedList([]), -diff --git a/Sources/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift -index 1bb5f1c..0d3eed9 100644 ---- a/Sources/FuzzilliCli/TerminalUI.swift -+++ b/Sources/FuzzilliCli/TerminalUI.swift -@@ -38,6 +38,40 @@ class TerminalUI { - } - } - -+ private func getProcessIDsForD8(_ d8Path: String) -> [pid_t] { -+ var pids: [pid_t] = [] -+ -+ let task = Process() -+ task.executableURL = URL(fileURLWithPath: "/bin/ps") -+ task.arguments = ["-e", "-o", "pid,command"] -+ -+ let pipe = Pipe() -+ task.standardOutput = pipe -+ -+ do { -+ try task.run() -+ } catch { -+ return [] -+ } -+ -+ let data = pipe.fileHandleForReading.readDataToEndOfFile() -+ if let output = String(data: data, encoding: .utf8) { -+ let lines = output.components(separatedBy: "\n") -+ for line in lines { -+ if line.contains(d8Path) && !line.contains("ps -e -o pid,command") && !line.contains("FuzzilliCli") { -+ let components = line.trimmingCharacters(in: .whitespacesAndNewlines).components(separatedBy: " ") -+ if let pid = pid_t(components[0]) { -+ pids.append(pid) -+ } -+ } -+ } -+ } -+ -+ task.waitUntilExit() -+ -+ return pids -+ } -+ - func initOnFuzzerQueue(_ fuzzer: Fuzzer) { - // Register log event listener now to be able to print log messages - // generated during fuzzer initialization -@@ -52,6 +86,13 @@ class TerminalUI { - } - } - -+ fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { diff in -+ if diff.reproducesInNonReplMode { -+ print("########## Unique Differential Found ##########") -+ print(fuzzer.lifter.lift(diff.program, withOptions: .includeComments)) -+ } -+ } -+ - fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { crash in - if crash.isUnique { - print("########## Unique Crash Found ##########") -@@ -90,12 +131,41 @@ class TerminalUI { - print() - } - -+ // Nuke stray d8 processes. Pretty terrible but it is what it is -+ // With default timeout 250ms this will nuke a d8 process if it survives longer than ~30 minutes -+ fuzzer.timers.scheduleTask(every: (15 * Minutes + Double.random(in: (1 * Minutes)...(10 * Minutes)))) { -+ let nukeAfterSeconds = ((Double(fuzzer.config.timeout) / 1000.0) * 8.0) * Double((fuzzer.runner as! REPRL).maxExecsBeforeRespawn) -+ let d8Path = fuzzer.runner.processArguments[0] -+ let pids = self.getProcessIDsForD8(d8Path) -+ for p in pids { -+ let statFilePath = "/proc/\(p)/stat" -+ -+ var fileStats = stat() -+ -+ if stat(statFilePath, &fileStats) == 0 { -+ let accessTime = Double(fileStats.st_atim.tv_sec) -+ -+ let currentTime = Date().timeIntervalSince1970 -+ -+ let secondsElapsed = currentTime - accessTime -+ if (secondsElapsed >= nukeAfterSeconds) { -+ let result = kill(p, SIGKILL) -+ if result == 0 { -+ print("Nuked stray d8 process \(p)") -+ } -+ } -+ } -+ } -+ } -+ - // Randomly sample generated and interesting programs and print them. - // The goal of this is to give users a better "feeling" for what the fuzzer is currently doing. -+ /* - fuzzer.timers.scheduleTask(every: 5 * Minutes) { - self.printNextInterestingProgram = true - self.printNextGeneratedProgram = true - } -+ */ - } - } - } -@@ -125,28 +195,49 @@ class TerminalUI { - } else { - print("Fuzzer Statistics") - } -+ -+ let bugOracleUsageRate = (Float(stats.relationsPerformed) / Float(stats.totalExecs)) * 100 -+ let jitUsageRate = (Float(stats.jitSamples) / Float(stats.totalExecs)) * 100 -+ -+ let cestDateFormatter = DateFormatter() -+ cestDateFormatter.dateFormat = "HH:mm:ss - dd.MM.yyyy" -+ -+ cestDateFormatter.timeZone = TimeZone(abbreviation: "CEST") -+ let date = Date() -+ - 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) -- 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) -+ Fuzzer state: \(state) -+ Uptime: \(formatTimeInterval(fuzzer.uptime())) -+ Current Time: \(cestDateFormatter.string(from: date)) -+ 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) -+ Differentials Found: \(stats.differentialSamples) -+ Sparkplug Executions: \(stats.sparkplugSamples) -+ Maglev Executions: \(stats.maglevSamples) -+ TurboFan Executions: \(stats.turbofanSamples) -+ Relations Performed: \(stats.relationsPerformed) -+ Bug Oracle Usage: \(String(format: "%.2f%%", bugOracleUsageRate)) -+ JIT Usage Rate: \(String(format: "%.2f%%", jitUsageRate)) -+ 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 -+ Avg. bug oracle execution time: \(Int(stats.avgBugOracleTime * 1000))ms -+ Avg. dump size (opt): \(String(format: "%.2f", stats.avgDumpSizeOpt / 1000.0))KB -+ Avg. dump size (unopt): \(String(format: "%.2f", stats.avgDumpSizeUnOpt / 1000.0))KB -+ 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) - """) - } - -diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift -index 98a9787..736e7de 100644 ---- a/Sources/FuzzilliCli/main.swift -+++ b/Sources/FuzzilliCli/main.swift -@@ -97,6 +97,9 @@ Options: - --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. -+ --dumpling-depth : Depth used during dumping to traverse objects (default: 3) -+ --dumpling-prop-count : Amount of properties/array elements to consider during dumping (default: 5) -+ - """) - exit(0) - } -@@ -152,6 +155,9 @@ let swarmTesting = args.has("--swarmTesting") - let argumentRandomization = args.has("--argumentRandomization") - let additionalArguments = args["--additionalArguments"] ?? "" - let tag = args["--tag"] -+let dumplingDepth = UInt32(args.int(for: "--dumpling-depth") ?? 3) -+let dumplingPropCount = UInt32(args.int(for: "--dumpling-prop-count") ?? 5) -+ - - guard numJobs >= 1 else { - configError("Must have at least 1 job") -@@ -363,12 +369,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) + ["--dumpling-depth=\(dumplingDepth)", "--dumpling-prop-count=\(dumplingPropCount)"] - logger.info("Using the following arguments for the target engine: \(jsShellArguments)") -+let jsShellRefArguments = profile.processArgsReference + ["--dumpling-depth=\(dumplingDepth)", "--dumpling-prop-count=\(dumplingPropCount)"] -+ -+func makeFuzzer(with configuration: Configuration, localId: UInt32) -> Fuzzer { -+ assert(localId >= 1) - --func makeFuzzer(with configuration: Configuration) -> Fuzzer { - // A script runner to execute JavaScript code in an instrumented JS engine. - let runner = REPRL(executable: jsShellPath, processArguments: jsShellArguments, processEnvironment: profile.processEnv, maxExecsBeforeRespawn: profile.maxExecsBeforeRespawn) -+ let referenceRunner = REPRL(executable: jsShellPath, processArguments: jsShellRefArguments, processEnvironment: profile.processEnv, maxExecsBeforeRespawn: profile.maxExecsBeforeRespawn) - - /// The mutation fuzzer responsible for mutating programs from the corpus and evaluating the outcome. - let disabledMutators = Set(profile.disabledMutators) -@@ -461,10 +471,11 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { - - // Minimizer to minimize crashes and interesting programs. - let minimizer = Minimizer() -- -+ - // Construct the fuzzer instance. - return Fuzzer(configuration: configuration, - scriptRunner: runner, -+ referenceRunner: referenceRunner, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, -@@ -473,21 +484,45 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { - environment: environment, - lifter: lifter, - corpus: corpus, -- minimizer: minimizer) -+ minimizer: minimizer, -+ localId: localId) - } - -+let cwd = FileManager.default.currentDirectoryPath -+#if DEBUG -+ public let relateToolPath = "\(cwd)/.build/debug/RelateTool" -+#else -+ public let relateToolPath = "\(cwd)/.build/release/RelateTool" -+#endif -+if !FileManager.default.fileExists(atPath: relateToolPath) { -+ logger.fatal("RelateTool not found in cwd (\(relateToolPath))") -+} -+if !FileManager.default.fileExists(atPath: "/usr/bin/timeout") { -+ logger.fatal("/usr/bin/timeout not found") -+} -+if !FileManager.default.fileExists(atPath: "/bin/ps") { -+ logger.fatal("/bin/ps not found") -+} -+ -+ - // The configuration of the main fuzzer instance. - let mainConfig = Configuration(arguments: CommandLine.arguments, - timeout: UInt32(timeout), - logLevel: logLevel, - crashTests: profile.crashTests, -+ differentialTests: profile.differentialTests, -+ differentialTestsInvariant: profile.differentialTestsInvariant, - minimizationLimit: minimizationLimit, - enableDiagnostics: diagnostics, - enableInspection: inspect, - staticCorpus: staticCorpus, -- tag: tag) -+ tag: tag, -+ relateToolPath: relateToolPath, -+ dumplingDepth: dumplingDepth, -+ dumplingPropCount: dumplingPropCount, -+ storagePath: storagePath) - --let fuzzer = makeFuzzer(with: mainConfig) -+let fuzzer = makeFuzzer(with: mainConfig, localId: 1) - - // Create a "UI". We do this now, before fuzzer initialization, so - // we are able to print log messages generated during initialization. -@@ -514,9 +549,6 @@ fuzzer.sync { - // Always want some statistics. - fuzzer.addModule(Statistics()) - -- // Check core file generation on linux, prior to moving corpus file directories -- fuzzer.checkCoreFileGeneration() -- - // Exit this process when the main fuzzer stops. - fuzzer.registerEventListener(for: fuzzer.events.ShutdownComplete) { reason in - if resume, let path = storagePath { -@@ -617,20 +649,27 @@ let workerConfig = Configuration(arguments: CommandLine.arguments, - timeout: UInt32(timeout), - logLevel: .warning, - crashTests: profile.crashTests, -+ differentialTests: profile.differentialTests, -+ differentialTestsInvariant: profile.differentialTestsInvariant, - minimizationLimit: minimizationLimit, - enableDiagnostics: false, - enableInspection: inspect, - staticCorpus: staticCorpus, -- tag: tag) -- --for _ in 1.. (status: Int32, exec_time: UInt64) { - var exec_time: UInt64 = 0 - var status: Int32 = 0 -+ var encodedJitState: UInt8 = 0 - code.withCString { -- status = reprl_execute(ctx, $0, UInt64(code.count), 1_000_000, &exec_time, 0) -+ // differentialFuzzingPositionDumpSeed == 0 for tests -+ status = reprl_execute(ctx, $0, UInt64(code.count), 1_000_000, &exec_time, 0, 0, &encodedJitState) - } - return (status, exec_time) - } -diff --git a/Sources/RelateTool/main.swift b/Sources/RelateTool/main.swift -new file mode 100644 -index 0000000..0007d8b ---- /dev/null -+++ b/Sources/RelateTool/main.swift -@@ -0,0 +1,114 @@ -+import Foundation -+import Fuzzilli -+ -+ -+func printRunningCmd(_ process: Process) { -+ print("Running command: \(process.executableURL!.path) \(process.arguments!.joined(separator: " "))") -+} -+ -+// -+// Process commandline arguments. -+// -+let args = Arguments.parse(from: CommandLine.arguments) -+ -+let jsShellPath = args["--d8"] ?? "/root/localTools/v8/out/fuzzbuild/d8" -+var poc = args["--poc"]! -+ -+let logLevel: OracleLogLevel -+if args["--logLevel"] == nil || args["--logLevel"] == "info" { -+ logLevel = .info -+} else if args["--logLevel"] == "debug" { -+ logLevel = .debug -+} else { -+ logLevel = .none -+} -+ -+let validate = args["--validate"] -+ -+let usePrepend = args["--prepend"] -+ -+let progOutput = args["--progOutput"] -+ -+if usePrepend != nil { -+ var prependPath = URL(fileURLWithPath: #file) -+ for _ in 0...2 { -+ prependPath.deleteLastPathComponent() -+ } -+ prependPath = prependPath.appendingPathComponent("prepend.js") -+ print(prependPath.path) -+ if !FileManager.default.fileExists(atPath: prependPath.path) { -+ print("prepend.js not found!") -+ exit(-1) -+ } -+ -+ let prependJS = try! String(contentsOfFile: prependPath.path) -+ -+ let filename = "prepend_" + URL(fileURLWithPath: poc).lastPathComponent -+ let fileURL = URL(fileURLWithPath: "/tmp").appendingPathComponent(filename) -+ -+ let prependedScript = prependJS + (try! String(contentsOfFile: poc)) -+ -+ do { -+ try prependedScript.write(to: fileURL, atomically: false, encoding: String.Encoding.utf8) -+ } catch { -+ print("Failed to write file \(fileURL): \(error)") -+ exit(-1) -+ } -+ -+ poc = fileURL.path -+} -+ -+let optRun = Process() -+ -+let optOutput = Pipe() -+optRun.standardOutput = optOutput -+optRun.standardError = optOutput -+ -+ -+let config = V8DifferentialConfig() -+ -+var g = SystemRandomNumberGenerator() -+let differentialFuzzingDumpSeed = UInt32(Int.random(in: 1...9999, using: &g)); -+ -+optRun.executableURL = URL(fileURLWithPath: jsShellPath) -+optRun.arguments = config.commonArgs + config.differentialArgs + ["--dumping-seed=\(differentialFuzzingDumpSeed)", poc] -+ -+printRunningCmd(optRun) -+try! optRun.run() -+optRun.waitUntilExit() -+if progOutput != nil { -+ print(String(data: optOutput.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)!) -+} -+let optDumps = try? String(contentsOfFile: "/tmp/\(differentialFuzzingDumpSeed)_output_dump.txt", encoding: .utf8) -+if optDumps == nil { -+ if validate == nil { -+ print("Produced no opt Dumps") -+ } else { -+ exit(1) -+ } -+} else { -+ let unOptRun = Process() -+ let unOptOutput = Pipe() -+ unOptRun.standardOutput = unOptOutput -+ unOptRun.standardError = unOptOutput -+ unOptRun.executableURL = URL(fileURLWithPath: jsShellPath) -+ unOptRun.arguments = config.commonArgs + config.referenceArgs + ["--dumping-seed=\(differentialFuzzingDumpSeed)", poc] -+ printRunningCmd(unOptRun) -+ try! unOptRun.run() -+ unOptRun.waitUntilExit() -+ if progOutput != nil { -+ print(String(data: unOptOutput.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)!) -+ } -+ let unOptDumps = try! String(contentsOfFile: "/tmp/\(differentialFuzzingDumpSeed)_output_dump.txt", encoding: .utf8) -+ let result = relate(optDumps!, with: unOptDumps, logLevel) -+ -+ if (usePrepend != nil) { -+ try? FileManager.default.removeItem(atPath: poc) -+ } -+ -+ if validate == nil { -+ print(result) -+ } else if !result { -+ exit(1) -+ } -+} -diff --git a/Sources/libreprl/include/libreprl.h b/Sources/libreprl/include/libreprl.h -index 1bfd693..777288b 100644 ---- a/Sources/libreprl/include/libreprl.h -+++ b/Sources/libreprl/include/libreprl.h -@@ -53,8 +53,9 @@ void reprl_destroy_context(struct reprl_context* ctx); - /// @param timeout The maximum allowed execution time in microseconds - /// @param execution_time A pointer to which, if execution succeeds, the execution time in microseconds is written to - /// @param fresh_instance if true, forces the creation of a new instance of the target -+/// @param execHash A pointer to which the differential testing execution hash is written to - /// @return A REPRL exit status (see below) or a negative number in case of an error --int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script_length, uint64_t timeout, uint64_t* execution_time, int fresh_instance); -+int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script_length, uint64_t timeout, uint64_t* execution_time, int fresh_instance, uint32_t source_pos_dump_seed, uint8_t* jit_state); - - /// Returns true if the execution terminated due to a signal. - /// -diff --git a/Sources/libreprl/libreprl-posix.c b/Sources/libreprl/libreprl-posix.c -index 43c4e48..94cc7f0 100644 ---- a/Sources/libreprl/libreprl-posix.c -+++ b/Sources/libreprl/libreprl-posix.c -@@ -30,12 +30,17 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include - -+// The REPRL protocol version. Must be identical between server and client. -+// Bump this up whenever there are non-backwards-compatible changes to the protocol -+#define REPRL_PROTOCOL_VERSION 2 -+ - // Well-known file descriptor numbers for reprl <-> child communication, child process side - #define REPRL_CHILD_CTRL_IN 100 - #define REPRL_CHILD_CTRL_OUT 101 -@@ -141,7 +146,7 @@ static struct data_channel* reprl_create_data_channel(struct reprl_context* ctx) - reprl_error(ctx, "Failed to mmap data channel file: %s", strerror(errno)); - return NULL; - } -- -+ - struct data_channel* channel = malloc(sizeof(struct data_channel)); - channel->fd = fd; - channel->mapping = mapping; -@@ -214,6 +219,19 @@ static int reprl_spawn_child(struct reprl_context* ctx) - _exit(-1); - } - -+ #ifdef __linux__ -+ // Set RLIMIT_CORE to 0, such that we don't produce core dumps. The -+ // added benefit of doing this here, in the child process, is that we -+ // can still get core dumps when Fuzzilli crashes. -+ struct rlimit core_limit; -+ core_limit.rlim_cur = 0; -+ core_limit.rlim_max = 0; -+ if (setrlimit(RLIMIT_CORE, &core_limit) < 0) { -+ fprintf(stderr, "setrlimit failed in the child: %s\n", strerror(errno)); -+ _exit(-1); -+ }; -+ #endif -+ - // Unblock any blocked signals. It seems that libdispatch sometimes blocks delivery of certain signals. - sigset_t newset; - sigemptyset(&newset); -@@ -259,21 +277,42 @@ static int reprl_spawn_child(struct reprl_context* ctx) - } - ctx->pid = pid; - -- char helo[5] = { 0 }; -- if (read(ctx->ctrl_in, helo, 4) != 4) { -+ char handshake[5] = { 0 }; -+ if (read(ctx->ctrl_in, handshake, 4) != 4) { - reprl_terminate_child(ctx); -- return reprl_error(ctx, "Did not receive HELO message from child: %s", strerror(errno)); -+ return reprl_error(ctx, "Did not receive handshake message from child: %s", strerror(errno)); - } -- -- if (strncmp(helo, "HELO", 4) != 0) { -+ -+ if (strncmp(handshake, "HELO", 4) == 0) { -+ // Client is using protocol version 1. - reprl_terminate_child(ctx); -- return reprl_error(ctx, "Received invalid HELO message from child: %s", helo); -+ return reprl_error(ctx, "The client uses an old version of the REPRL protocol, please update it to the latest version"); - } -- -- if (write(ctx->ctrl_out, helo, 4) != 4) { -+ -+ if (strncmp(handshake, "XDXD", 4) != 0) { -+ reprl_terminate_child(ctx); -+ return reprl_error(ctx, "Received invalid handshake message from child: %s", handshake); -+ } -+ -+ // The server side just sends back the handshake message, but not the protocol version. -+ if (write(ctx->ctrl_out, handshake, 4) != 4) { -+ reprl_terminate_child(ctx); -+ return reprl_error(ctx, "Failed to send handshake reply message to child: %s", strerror(errno)); -+ } -+ -+ #ifdef __linux__ -+ struct rlimit core_limit = {}; -+ if (prlimit(pid, RLIMIT_CORE, NULL, &core_limit) < 0) { - reprl_terminate_child(ctx); -- return reprl_error(ctx, "Failed to send HELO reply message to child: %s", strerror(errno)); -+ return reprl_error(ctx, "prlimit failed: %s\n", strerror(errno)); - } -+ if (core_limit.rlim_cur != 0 || core_limit.rlim_max != 0) { -+ reprl_terminate_child(ctx); -+ return reprl_error(ctx, "Detected non-zero RLIMIT_CORE. Check that the child does not set RLIMIT_CORE manually.\n"); -+ } -+ #endif -+ -+ - - return 0; - } -@@ -326,20 +365,20 @@ int reprl_initialize_context(struct reprl_context* ctx, const char** argv, const - void reprl_destroy_context(struct reprl_context* ctx) - { - reprl_terminate_child(ctx); -- -+ - free_string_array(ctx->argv); - free_string_array(ctx->envp); -- -+ - reprl_destroy_data_channel(ctx->data_in); - reprl_destroy_data_channel(ctx->data_out); - reprl_destroy_data_channel(ctx->child_stdout); - reprl_destroy_data_channel(ctx->child_stderr); -- -+ - free(ctx->last_error); - free(ctx); - } - --int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script_length, uint64_t timeout, uint64_t* execution_time, int fresh_instance) -+int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script_length, uint64_t timeout, uint64_t* execution_time, int fresh_instance, uint32_t source_pos_dump_seed, uint8_t* jit_state) - { - if (!ctx->initialized) { - return reprl_error(ctx, "REPRL context is not initialized"); -@@ -363,11 +402,14 @@ int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script - lseek(ctx->data_in->fd, 0, SEEK_SET); - if (ctx->child_stdout) { - lseek(ctx->child_stdout->fd, 0, SEEK_SET); -+ -+ memset(ctx->child_stdout->mapping, 0, REPRL_MAX_DATA_SIZE); - } -+ - if (ctx->child_stderr) { - lseek(ctx->child_stderr->fd, 0, SEEK_SET); - } -- -+ - // Spawn a new instance if necessary. - if (!ctx->pid) { - int r = reprl_spawn_child(ctx); -@@ -379,6 +421,7 @@ int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script - - // Tell child to execute the script. - if (write(ctx->ctrl_out, "exec", 4) != 4 || -+ write(ctx->ctrl_out, &source_pos_dump_seed, sizeof(source_pos_dump_seed)) != sizeof(source_pos_dump_seed) || - write(ctx->ctrl_out, &script_length, 8) != 8) { - // These can fail if the child unexpectedly terminated between executions. - // Check for that here to be able to provide a better error message. -@@ -408,13 +451,26 @@ int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script - // We expect all signal handlers to be installed with SA_RESTART, so receiving EINTR here is unexpected and thus also an error. - return reprl_error(ctx, "Failed to poll: %s", strerror(errno)); - } -- -+ - // Poll succeeded, so there must be something to read now (either the status or EOF). -+ #pragma pack(1) -+ struct { -+ int status; -+ uint8_t jit_state; -+ } s; -+ // we only want to read 5 bytes and not care about padding -+ // just to be sure for the future -+ const size_t ssize = 5; -+ -+ -+ ssize_t rv = read(ctx->ctrl_in, &s, ssize); - int status; -- ssize_t rv = read(ctx->ctrl_in, &status, 4); -+ -+ // printf("---STDOUT---\n%s\n", reprl_fetch_stdout(ctx)); -+ // printf("---STDERR---\n%s\n", reprl_fetch_stderr(ctx)); - if (rv < 0) { - return reprl_error(ctx, "Failed to read from control pipe: %s", strerror(errno)); -- } else if (rv != 4) { -+ } else if (rv != ssize) { - // Most likely, the child process crashed and closed the write end of the control pipe. - // Unfortunately, there probably is nothing that guarantees that waitpid() will immediately succeed now, - // and we also don't want to block here. So just retry waitpid() a few times... -@@ -423,7 +479,6 @@ int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script - success = waitpid(ctx->pid, &status, WNOHANG) == ctx->pid; - if (!success) usleep(10); - } while (!success && current_usecs() - start_time < timeout); -- - if (!success) { - // Wait failed, so something weird must have happened. Maybe somehow the control pipe was closed without the child exiting? - // Probably the best we can do is kill the child and return an error. -@@ -443,7 +498,11 @@ int reprl_execute(struct reprl_context* ctx, const char* script, uint64_t script - return reprl_error(ctx, "Waitpid returned unexpected child state %i", status); - } - } -- -+ else { -+ status = s.status; -+ *jit_state = s.jit_state; -+ } -+ - // The status must be a positive number, see the status encoding format below. - // We also don't allow the child process to indicate a timeout. If we wanted, - // we could treat it as an error if the upper bits are set. -diff --git a/prepend.js b/prepend.js -new file mode 100644 -index 0000000..104c9c2 ---- /dev/null -+++ b/prepend.js -@@ -0,0 +1,282 @@ -+const prettyPrinted = function prettyPrinted(msg) { return console.log(msg); }; -+// Mock Math.random. -+(function() { -+ let index = 1; -+ Math.random = function() { -+ const x = Math.sin(index++) * 10000; -+ return x - Math.floor(x); -+ } -+})(); -+// Mock Math.pow. Work around an optimization for -0.5. -+(function() { -+ const origMathPow = Math.pow; -+ Math.pow = function(a, b) { -+ if (b === -0.5) { -+ return 0; -+ } else { -+ return origMathPow(a, b); -+ } -+ } -+})(); -+// Mock Date. -+(function() { -+ let index = 0; -+ let mockDate = 1477662728696; -+ const mockDateNow = function() { -+ index = (index + 1) % 10; -+ mockDate = mockDate + index + 1; -+ return mockDate; -+ } -+ const origDate = Date; -+ const construct = Reflect.construct; -+ const constructDate = function(args) { -+ let result; -+ if (args.length) { -+ result = construct(origDate, args); -+ } else { -+ result = new origDate(mockDateNow()); -+ } -+ result.constructor = function(...args) { return constructDate(args); } -+ Object.defineProperty( -+ result, "constructor", { configurable: false, writable: false }); -+ return result; -+ } -+ origDate.prototype.constructor = function(...args) { -+ return constructDate(args); -+ }; -+ var handler = { -+ apply: function(target, thisArg, args) { -+ return constructDate(args); -+ }, -+ construct: function(target, args, newTarget) { -+ return constructDate(args); -+ }, -+ get: function(target, property, receiver) { -+ if (property == "now") { -+ return mockDateNow; -+ } -+ if (property == "prototype") { -+ return origDate.prototype; -+ } -+ }, -+ } -+ Date = new Proxy(Date, handler); -+})(); -+// Mock this.performance. -+(function() { -+ function mockPerformanceMark(name) { -+ return {entryType: "mark", name: name, startTime: 0.0, duration: 0} -+ } -+ function mockPerformanceMeasure(name) { -+ return {entryType: "measure", name: name, startTime: 0.0, duration: 0} -+ } -+ -+ var handler = { -+ get: function(target, property, receiver) { -+ if (property == "now") { -+ return 1.1; -+ } -+ if (property == "prototype") { -+ return undefined; -+ } -+ if (property == "mark") { -+ return mockPerformanceMark; -+ } -+ if (property == "measure") { -+ return mockPerformanceMeasure; -+ } -+ if (property == "measureMemory") { -+ return []; -+ } -+ }, -+ } -+ this.performance = new Proxy(this.performance, handler); -+})(); -+// Mock readline so that test cases don't hang. -+readline = function() { return "foo"; }; -+// Mock stack traces. -+Error.prepareStackTrace = function(error, structuredStackTrace) { -+ return ""; -+}; -+Object.defineProperty( -+ Error, 'prepareStackTrace', { configurable: false, writable: false }); -+// Mock buffer access in float typed arrays because of varying NaN patterns. -+(function() { -+ const origArrayFrom = Array.from; -+ const origArrayIsArray = Array.isArray; -+ const origFunctionPrototype = Function.prototype; -+ const origIsNaN = isNaN; -+ const origIterator = Symbol.iterator; -+ const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; }; -+ const mock = function(type) { -+ // Remove NaN values from parameters to "set" function. -+ const set = type.prototype.set; -+ type.prototype.set = function(array, offset) { -+ if (Array.isArray(array)) { -+ array = array.map(deNaNify); -+ } -+ set.apply(this, [array, offset]); -+ }; -+ const handler = { -+ // Remove NaN values from parameters to constructor. -+ construct: function(target, args) { -+ for (let i = 0; i < args.length; i++) { -+ if (args[i] != null && -+ typeof args[i][origIterator] === 'function') { -+ // Consume iterators. -+ args[i] = origArrayFrom(args[i]); -+ } -+ if (origArrayIsArray(args[i])) { -+ args[i] = args[i].map(deNaNify); -+ } -+ } -+ const obj = new ( -+ origFunctionPrototype.bind.call(type, null, ...args)); -+ return new Proxy(obj, { -+ get: function(x, prop) { -+ if (typeof x[prop] == "function") -+ return x[prop].bind(obj); -+ return x[prop]; -+ }, -+ // Remove NaN values that get assigned. -+ set: function(target, prop, value, receiver) { -+ target[prop] = deNaNify(value); -+ return value; -+ } -+ }); -+ }, -+ }; -+ return new Proxy(type, handler); -+ } -+ Float32Array = mock(Float32Array); -+ Float64Array = mock(Float64Array); -+})(); -+// Mock buffer access via DataViews because of varying NaN patterns. -+(function() { -+ const origIsNaN = isNaN; -+ const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; }; -+ const origSetFloat32 = DataView.prototype.setFloat32; -+ DataView.prototype.setFloat32 = function(offset, value, ...rest) { -+ origSetFloat32.call(this, offset, deNaNify(value), ...rest); -+ }; -+ const origSetFloat64 = DataView.prototype.setFloat64; -+ DataView.prototype.setFloat64 = function(offset, value, ...rest) { -+ origSetFloat64.call(this, offset, deNaNify(value), ...rest); -+ }; -+})(); -+// Mock maximum typed-array buffer and limit to 1MiB. Otherwise we might -+// get range errors. We ignore those by crashing, but that reduces coverage, -+// hence, let's reduce the range-error rate. -+(function() { -+ // Math.min might be manipulated in test cases. -+ const min = Math.min; -+ const maxBytes = 1048576; -+ const mock = function(type) { -+ const maxLength = maxBytes / (type.BYTES_PER_ELEMENT || 1); -+ const handler = { -+ construct: function(target, args) { -+ if (args[0] && typeof args[0] != "object") { -+ // Length used as first argument. -+ args[0] = min(maxLength, Number(args[0])); -+ } else if (args[0] instanceof ArrayBuffer && args.length > 1) { -+ // Buffer used as first argument. -+ const buffer = args[0]; -+ args[1] = Number(args[1]); -+ // Ensure offset is multiple of bytes per element. -+ args[1] = args[1] - (args[1] % type.BYTES_PER_ELEMENT); -+ // Limit offset to length of buffer. -+ args[1] = min(args[1], buffer.byteLength || 0); -+ if (args.length > 2) { -+ // If also length is given, limit it to the maximum that's possible -+ // given buffer and offset. Avoid NaN offset turning the length -+ // NaN, too. -+ const maxBytesLeft = buffer.byteLength - (args[1] || 0); -+ const maxLengthLeft = maxBytesLeft / type.BYTES_PER_ELEMENT; -+ args[2] = min(Number(args[2]), maxLengthLeft); -+ } -+ } -+ return new (Function.prototype.bind.apply(type, [null].concat(args))); -+ }, -+ }; -+ return new Proxy(type, handler); -+ } -+ ArrayBuffer = mock(ArrayBuffer); -+ SharedArrayBuffer = mock(SharedArrayBuffer); -+ Int8Array = mock(Int8Array); -+ Uint8Array = mock(Uint8Array); -+ Uint8ClampedArray = mock(Uint8ClampedArray); -+ Int16Array = mock(Int16Array); -+ Uint16Array = mock(Uint16Array); -+ Int32Array = mock(Int32Array); -+ Uint32Array = mock(Uint32Array); -+ BigInt64Array = mock(BigInt64Array); -+ BigUint64Array = mock(BigUint64Array); -+ Float32Array = mock(Float32Array); -+ Float64Array = mock(Float64Array); -+})(); -+// Mock typed array set function and cap offset to not throw a range error. -+(function() { -+ // Math.min might be manipulated in test cases. -+ const min = Math.min; -+ const types = [ -+ Int8Array, -+ Uint8Array, -+ Uint8ClampedArray, -+ Int16Array, -+ Uint16Array, -+ Int32Array, -+ Uint32Array, -+ BigInt64Array, -+ BigUint64Array, -+ Float32Array, -+ Float64Array, -+ ]; -+ for (const type of types) { -+ const set = type.prototype.set; -+ type.prototype.set = function(array, offset) { -+ if (Array.isArray(array)) { -+ offset = Number(offset); -+ offset = min(offset, this.length - array.length); -+ } -+ set.call(this, array, offset); -+ }; -+ } -+})(); -+// Mock Worker. -+(function() { -+ let index = 0; -+ const workerMessages = [ -+ undefined, 0, -1, "", "foo", 42, [], {}, [0], {"x": 0} -+ ]; -+ Worker = function(code){ -+ try { -+ print(prettyPrinted(eval(code))); -+ } catch(e) { -+ print(prettyPrinted(e)); -+ } -+ this.getMessage = function(){ -+ index = (index + 1) % 10; -+ return workerMessages[index]; -+ } -+ this.postMessage = function(msg){ -+ print(prettyPrinted(msg)); -+ } -+ }; -+})(); -+// Mock Realm. -+Realm.eval = function(realm, code) { return eval(code) }; -+// Mock the nondeterministic parts of WeakRef and FinalizationRegistry. -+WeakRef.prototype.deref = function() { }; -+FinalizationRegistry = function(callback) { }; -+FinalizationRegistry.prototype.register = function(target, holdings) { }; -+FinalizationRegistry.prototype.unregister = function(unregisterToken) { }; -+FinalizationRegistry.prototype.cleanupSome = function() { }; -+FinalizationRegistry.prototype[Symbol.toStringTag] = "FinalizationRegistry"; -+// Mock the nondeterministic Atomics.waitAsync. -+Atomics.waitAsync = function() { -+ // Return a mock "Promise" whose "then" function will call the callback -+ // immediately. -+ return {'value': {'then': function (f) { f(); }}}; -+} -+// Mock serializer API with no-ops. -+d8.serializer = {'serialize': (x) => x, 'deserialize': (x) => x}; diff --git a/Sources/FuzzILTool/main.swift b/Sources/FuzzILTool/main.swift index a8a3b6009..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,15 +173,21 @@ 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) } let ast: JavaScriptParser.AST do { ast = try parser.parse(path) + } catch JavaScriptParser.ParserError.parsingFailed(let error) { + // Unwrap the JS parse error here to format its linebreaks. + print("Failed to parse \(path):\n\(error)") + exit(-1) } catch { - print("Failed to parse \(path): \(error)") + print("Failed to parse \(path):\n\(error)") exit(-1) } @@ -188,9 +201,11 @@ else if args.has("--compile") { } if let js_path = args["--outputPathJS"] { - let content = jsLifter.lift(program) + 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) @@ -201,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 { @@ -212,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) @@ -221,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 38d6992dd..6d706e0cb 100644 --- a/Sources/Fuzzilli/Base/ContextGraph.swift +++ b/Sources/Fuzzilli/Base/ContextGraph.swift @@ -16,7 +16,7 @@ import Collections public class ContextGraph { // This is an edge, it holds all Generators that provide the `to` context at some point. - // Another invariant is that each Generator will keep the original context, i.e. it will return to the `from` conetxt. + // Another invariant is that each Generator will keep the original context, i.e. it will return to the `from` context. struct EdgeKey: Hashable { let from: Context let to: Context @@ -54,42 +54,72 @@ 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) { - // 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() + public init( + for generators: WeightedList, isBundle: Bool, withLogger logger: Logger + ) { + assertBasicConsistency(in: generators) + 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. + // One example is a GeneratorStub that opens a context, then calls build manually without it being split into two stubs where we have a yield point to assemble a synthetic generator. + self.edges = [:] for generator in generators { - generator.providedContexts.forEach { ctx in - providedContexts.insert(ctx) + for providableContext in generator.providedContexts { + let edge = EdgeKey(from: generator.requiredContext, to: providableContext) + self.edges[edge, default: GeneratorEdge()].addGenerator(generator) } - - requiredContexts.insert(generator.requiredContext) } + } - // Check that every part that provides something is used by the next part of the Generator. This is a simple consistency check. + // Check that every part that provides something is used by the next part of the Generator. This is a simple consistency check. + private func assertBasicConsistency(in generators: WeightedList) { for generator in generators where generator.parts.count > 1 { var currentContext = Context(generator.parts[0].providedContext) for i in 1.., isBundle: Bool, withLogger logger: Logger + ) { + // 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 { + generator.providedContexts.forEach { ctx in + providedContexts.insert(ctx) + } + requiredContexts.insert(generator.requiredContext) + } 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.") + 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." + ) } @@ -97,19 +127,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)") - } - } - - // 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. - // One example is a GeneratorStub that opens a context, then calls build manually without it being split into two stubs where we have a yield point to assemble a synthetic generator. - self.edges = [:] - - for generator in generators { - for providableContext in generator.providedContexts { - let edge = EdgeKey(from: generator.requiredContext, to: providableContext) - self.edges[edge, default: GeneratorEdge()].addGenerator(generator) + logger.warning( + "Generator \(generator.name) provides a context that is never required by another generator \(generator.providedContexts)" + ) } } } @@ -133,7 +153,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]) @@ -149,7 +170,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) @@ -179,7 +200,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) @@ -214,9 +236,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 c0e23bd2f..b087363d1 100644 --- a/Sources/Fuzzilli/Base/Contributor.swift +++ b/Sources/Fuzzilli/Base/Contributor.swift @@ -28,6 +28,8 @@ public class Contributor: Hashable { private var timedOutSamples = 0 // Number of crashing programs produced. private var crashingSamples = 0 + // The number of programs resulting in valid differential produced. + private var differentialSamples = 0 // The number of times this contributor has been invoked private(set) var invocationCount = 0 // The number of times this contributor has actually emitted more than 0 instructions @@ -46,6 +48,10 @@ public class Contributor: Hashable { validSamples += 1 } + func generatedDifferentialSample() { + differentialSamples += 1 + } + func generatedInterestingSample() { interestingSamples += 1 } @@ -82,8 +88,13 @@ public class Contributor: Hashable { return crashingSamples } + public var differentialsFound: Int { + return differentialSamples + } + public var totalSamples: Int { - return validSamples + interestingSamples + invalidSamples + timedOutSamples + crashingSamples + 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. @@ -151,4 +162,8 @@ extension Contributors { public func generatedTimeOutSample() { forEach { $0.generatedTimeOutSample() } } + + public func generatedDifferentialSample() { + forEach { $0.generatedDifferentialSample() } + } } diff --git a/Sources/Fuzzilli/Base/Events.swift b/Sources/Fuzzilli/Base/Events.swift index 7006829bd..f353f58ab 100644 --- a/Sources/Fuzzilli/Base/Events.swift +++ b/Sources/Fuzzilli/Base/Events.swift @@ -53,7 +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) + >() /// Signals that a program causing a timeout has been found. public let TimeOutFound = Event() @@ -91,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. @@ -140,4 +147,15 @@ public enum ExecutionPurpose { case runtimeAssistedMutation /// Any other reason. case other + + // This variable is added because we currently don't want to differentially execute + // a sample if the purpose is unknown (`.other`), `.startup` or `.runtimeAssistedMutation`. + public var supportsDifferentialRun: Bool { + switch self { + case .fuzzing, .checkForDeterministicBehavior, .programImport, .minimization: + return true + case .startup, .runtimeAssistedMutation, .other: + return false + } + } } diff --git a/Sources/Fuzzilli/Base/Logging.swift b/Sources/Fuzzilli/Base/Logging.swift index c36eabfb7..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 @@ -28,6 +28,7 @@ public enum LogLevel: Int { /// Logs messages to the active fuzzer instance or prints them to stdout if no fuzzer is active. public class Logger { + public static var defaultLogLevelWithoutFuzzer = LogLevel.verbose private let label: String public init(withLabel label: String) { @@ -39,7 +40,7 @@ public class Logger { if fuzzer.config.logLevel.isAtLeast(level) { fuzzer.dispatchEvent(fuzzer.events.Log, data: (fuzzer.id, level, label, message)) } - } else { + } else if Logger.defaultLogLevelWithoutFuzzer.isAtLeast(level) { print("[\(label)] \(message)") } } diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 940b8d4af..2ca4a0d0b 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) @@ -35,17 +35,18 @@ public class ProgramBuilder { return data[key]!.pop() } - // Fetch the most recent value for this key and push it back. - public func popAndPush(_ key: String) -> Variable { + // Fetch the most recent value for this key but keep it. (As the entries act as a stack, + // another CodeGeneratorStub will still need to pop the entry later on.) + public func peek(_ key: String) -> Variable { assert(data[key] != nil) return data[key]!.top } 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) } @@ -57,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() @@ -72,39 +73,11 @@ public class ProgramBuilder { return contextAnalyzer.context } - /// If true, the variables containing a function is hidden inside the function's body. - /// - /// For example, in - /// - /// let f = b.buildPlainFunction(with: .parameters(n: 2) { args in - /// // ... - /// } - /// b.callFunction(f, withArgs: b.randomArguments(forCalling: f)) - /// - /// The variable f would *not* be visible inside the body of the plain function during building - /// when this is enabled. However, the variable will be visible during future mutations, it is only - /// hidden when the function is initially created. - /// - /// The same is done for class definitions, which may also cause trivial recursion in the constructor, - /// but where usage of the output inside the class definition's body may also cause other problems, - /// for example since `class C { [C] = 42; }` is invalid. - /// - /// This can make sense for a number of reasons. First, it prevents trivial recursion where a - /// function directly calls itself. Second, it prevents weird code like for example the following: - /// - /// function f1() { - /// let o6 = { x: foo + foo, y() { return foo; } }; - /// } - /// - /// From being generated, which can happen quite frequently during prefix generation as - /// the number of visible variables may be quite small. - public let enableRecursionGuard = true - /// Counter to quickly determine the next free variable. 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. @@ -134,17 +107,6 @@ public class ProgramBuilder { /// literals is created inside a method/getter/setter of another object literals. private var activeObjectLiterals = Stack() - /// If we open a new function, we save its Variable here. - /// This allows CodeGenerators to refer to their Variable after they emit the - /// `End*Function` operation. This allows them to call the function after closing it. - /// Since they cannot refer to the Variable as it usually is created in the head part of the Generator. - private var lastFunctionVariables = Stack() - - /// Just a getter to get the top most, i.e. last function Variable. - public var lastFunctionVariable: Variable { - return lastFunctionVariables.top - } - /// When building object literals, the state for the current literal is exposed through this member and /// can be used to add fields to the literal or to determine if some field already exists. public var currentObjectLiteral: ObjectLiteral { @@ -177,11 +139,17 @@ public class ProgramBuilder { } /// The remaining CodeGenerators to call as part of a building / CodeGen step, these will "clean up" the state and fix the contexts. - public var scheduled: Stack = Stack() + private var scheduled: Stack = Stack() // Runtime data that can be shared between different stubs within a CodeGenerator. var runtimeData = GeneratorRuntimeData() + /// + /// Adoption of variables from a different program. + /// Required when copying instructions between programs. + /// + private var varMaps = [VariableMap]() + /// Stack of active switch blocks. private var activeSwitchBlocks = Stack() @@ -223,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) { + if fuzzer.config.logLevel.isAtLeast(.verbose) { self.buildLog = BuildLog() } + code = Code(isBundle: isBundle) + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) } /// Resets this builder. @@ -244,18 +217,24 @@ public class ProgramBuilder { variablesInScope.removeAll() hiddenVariables.removeAll() numberOfHiddenVariables = 0 - contextAnalyzer = ContextAnalyzer() + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) jsTyper.reset() activeObjectLiterals.removeAll() activeClassDefinitions.removeAll() + activeSwitchBlocks.removeAll() + activeWasmModule = nil + argumentGenerationSignature.removeAll() + argumentGenerationVariableBudget.removeAll() buildLog?.reset() runtimeData.reset() + varMaps.removeAll() } /// 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 } @@ -317,39 +296,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) @@ -373,48 +360,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()) - }, { - String.random(ofLength: Int.random(in: 1...5)) - }) + 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 { @@ -422,13 +422,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 @@ -437,21 +441,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 } @@ -514,15 +522,23 @@ public class ProgramBuilder { return chooseUniform(from: fuzzer.environment.customMethods) } + /// Returns a random custom private method name. + /// + /// As above but for private methods, where a # symbol will be prepended. + public func randomCustomPrivateMethodName() -> String { + return chooseUniform(from: fuzzer.environment.customPrivateMethods) + } + /// Returns either a builtin or a custom method name, with equal probability. public func randomMethodName() -> String { return probability(0.5) ? randomBuiltinMethodName() : randomCustomMethodName() } 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 { @@ -538,15 +554,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. @@ -566,8 +584,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 @@ -597,7 +620,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) } @@ -628,7 +652,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) @@ -667,7 +693,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. @@ -687,7 +713,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) @@ -712,7 +740,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 } @@ -730,9 +760,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) } @@ -740,78 +774,125 @@ 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()) }), - (.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) + ( + .integer, + { type.isEnumeration ? self.loadEnum(type) : 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) + } + 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) - }), - (.function(), { + } + ), + (.iterable, { return self.createArray(with: [self.randomJsVariable()]) }), + ( + .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 { type in - 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 @@ -820,78 +901,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: { producedType in - producedType.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) - // The generator we ran above is supposed to generate the - // requested type. If no variable of that type exists - // now, then either the generator or its annotation is - // wrong. - return self.randomVariable(ofTypeOrSubtype: 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.") + } + 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,6 +992,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] { @@ -926,7 +1008,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) @@ -961,7 +1047,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 @@ -1007,7 +1094,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) } } @@ -1024,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. @@ -1079,7 +1170,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) } @@ -1087,7 +1180,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) } @@ -1095,14 +1190,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) }) @@ -1112,7 +1210,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) @@ -1130,7 +1230,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. @@ -1138,7 +1237,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]() @@ -1164,7 +1265,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 @@ -1188,8 +1290,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]) } @@ -1197,20 +1303,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 { @@ -1256,19 +1369,52 @@ public class ProgramBuilder { numberOfHiddenVariables -= 1 } + /// Hides a variable containing a function from the function's body. + /// + /// For example, in + /// + /// let f = b.buildPlainFunction(with: .parameters(n: 2) { args in + /// // ... + /// } + /// b.callFunction(f, withArgs: b.randomArguments(forCalling: f)) + /// + /// The variable f would *not* be visible inside the body of the plain function during building + /// when this is enabled. However, the variable will be visible during future mutations, it is only + /// hidden when the function is initially created. + /// + /// The same is done for class definitions, which may also cause trivial recursion in the constructor, + /// but where usage of the output inside the class definition's body may also cause other problems, + /// for example since `class C { [C] = 42; }` is invalid. + /// + /// This can make sense for a number of reasons. First, it prevents trivial recursion where a + /// function directly calls itself. Second, it prevents weird code like for example the following: + /// + /// function f1() { + /// let o6 = { x: foo + foo, y() { return foo; } }; + /// } + /// + /// 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: () -> Void) { + hide(variableToHide) + body() + unhide(variableToHide) + } + + // TODO(pawkra): enable shared types. private static func matchingWasmTypes(jsType: ILType) -> [ILType] { if jsType.Is(.integer) { return [.wasmi32, .wasmf64, .wasmf32] } else if jsType.Is(.number) { - return [.wasmf32, .wasmf64, .wasmi32, .wasmRefI31, .wasmI31Ref] + return [.wasmf32, .wasmf64, .wasmi32, .wasmRefI31(), .wasmI31Ref()] } else if jsType.Is(.bigint) { return [.wasmi64] } else if jsType.Is(.function()) { // TODO(gc): Add support for specific signatures. - return [.wasmFuncRef] + return [.wasmFuncRef()] } else { // TODO(gc): Add support for types of the anyref hierarchy. - return [.wasmExternRef] + return [.wasmExternRef()] } } @@ -1278,6 +1424,7 @@ public class ProgramBuilder { } // Helper that converts a Wasm type to its deterministic known JS counterparts. + // TODO(pawkra): enable shared types. private static func mapWasmToJsType(_ type: ILType) -> ILType { if type.Is(.wasmi32) { return .integer @@ -1294,12 +1441,14 @@ public class ProgramBuilder { return .jsAnything } else if type.Is(.nothing) { return .undefined - } else if type.Is(.wasmFuncRef) { + } else if type.Is(.wasmFuncRef()) { // TODO(cffsmith): refine this type with the signature if we can. return .function() - } else if type.Is(.wasmI31Ref) { + } 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 @@ -1311,10 +1460,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. @@ -1351,6 +1503,10 @@ public class ProgramBuilder { jsTyper.setType(of: variable, to: variableType) } + public func getWasmTypeDef(for type: ILType) -> Variable { + jsTyper.getWasmTypeDef(for: type) + } + /// This helper function converts parameter types into argument types, for example by "unrolling" rest parameters and handling optional parameters. private static func prepareArgumentTypes(forParameters params: ParameterList) -> [ILType] { var argumentTypes = [ILType]() @@ -1376,7 +1532,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 { @@ -1395,17 +1553,11 @@ public class ProgramBuilder { return argumentTypes } + /// Prepare for adoption of variables from another program. /// - /// Adoption of variables from a different program. - /// Required when copying instructions between program. - /// - private var varMaps = [VariableMap]() - - /// Prepare for adoption of variables from the given program. - /// - /// This sets up a mapping for variables from the given program to the + /// This sets up a mapping for variables from another program to the /// currently constructed one to avoid collision of variable names. - public func beginAdoption(from program: Program) { + public func beginAdoption() { varMaps.append(VariableMap()) } @@ -1414,9 +1566,9 @@ public class ProgramBuilder { varMaps.removeLast() } - /// Executes the given block after preparing for adoption from the provided program. - public func adopting(from program: Program, _ block: () -> Void) { - beginAdoption(from: program) + /// Executes the given block after preparing for adoption. + public func adopting(_ block: () -> Void) { + beginAdoption() block() endAdoption() } @@ -1431,7 +1583,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) } @@ -1453,7 +1606,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(from: program) { + adopting { for instr in program.code { adopt(instr) } @@ -1468,7 +1621,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. @@ -1477,7 +1629,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: @@ -1543,7 +1697,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) { @@ -1584,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() @@ -1604,7 +1759,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) { @@ -1617,13 +1774,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) @@ -1637,14 +1799,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) @@ -1665,13 +1833,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. @@ -1710,7 +1880,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 { @@ -1792,16 +1963,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" } } } @@ -1809,14 +1980,14 @@ public class ProgramBuilder { struct BuildAction { var name: String var outcome = ActionOutcome.started - var produces: [ILType] + var produces: [GeneratorStub.Constraint] } var pendingActions: Stack = Stack() var actions = [(BuildAction, Int)]() var indent = 0 - mutating func startAction(_ actionName: String, produces: [ILType]) { + mutating func startAction(_ actionName: String, produces: [GeneratorStub.Constraint]) { let action = BuildAction(name: actionName, produces: produces) // Mark this action as `.started`. actions.append((action, indent)) @@ -1831,19 +2002,19 @@ public class ProgramBuilder { finishedAction.outcome = .success actions.append((finishedAction, indent)) #if DEBUG - // Now Check that we've seen these new types. - for t in finishedAction.produces { - if !newlyCreatedVariableTypes.contains(where: { - $0.Is(t) - }) { - 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 expected type \(t)" - 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 } @@ -1864,21 +2035,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. @@ -1896,15 +2068,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. @@ -1924,14 +2097,20 @@ 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( + isBundle || 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 @@ -1957,7 +2136,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) @@ -2053,12 +2233,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. @@ -2070,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) @@ -2095,16 +2284,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)) } @@ -2124,33 +2316,41 @@ public class ProgramBuilder { var numberOfGeneratedInstructions = 0 // Calculate all input requirements of this CodeGenerator. - let inputTypes = Set(generator.parts.reduce([]) { res, gen in - return res + gen.inputs.types - }) + let inputRequirements = Set( + generator.parts.reduce([]) { res, gen in + return res + gen.inputs.constraints + }) - var availableTypes = inputTypes.filter { - randomVariable(ofType: $0) != nil + var fulfilledRequirements = inputRequirements.filter { requirement in + findVariable { requirement.fulfilled(by: self.type(of: $0)) } != nil } // Add the current context to the seen Contexts as well. var seenContexts: [Context] = [context] - let contextsAndTypes = generator.parts.map { ($0.providedContext, $0.inputs.types) } + 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, types) in contextsAndTypes { + for (contexts, requirements) in contextsAndRequirements { // We've seen the current context. for context in contexts { seenContexts.append(context) } - for type in types { + for requirement in requirements { // If we don't have the type available, check if we can produce it in the current context or a seen context. - if !availableTypes.contains(where: { - type.Is($0) - }) { + 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). @@ -2162,17 +2362,20 @@ public class ProgramBuilder { // Filter to see if they produce this type. Crucially to avoid dependency cycles, these also need to be valuegenerators. let canProduceThisType = callableGenerators.contains(where: { generator in - generator.produces.contains(where: { $0.Is(type) }) + generator.produces.contains(where: { requirement.fulfilled(by: $0) }) }) // 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 \(type) 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. - availableTypes.insert(type) + fulfilledRequirements.insert(requirement) } } } @@ -2180,7 +2383,7 @@ public class ProgramBuilder { // Try to create the types that we need for this generator. // At this point we've guaranteed that we can produce the types somewhere along the yield points of this generator. - createRequiredInputVariables(forTypes: inputTypes) + createRequiredInputVariables(for: inputRequirements) // Push the remaining stubs, we need to call them to close all Contexts properly. for part in generator.tail.reversed() { @@ -2196,26 +2399,29 @@ 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 { let codeSizePre = code.count // Check if we need to or can create types here. - createRequiredInputVariables(forTypes: inputTypes) + createRequiredInputVariables(for: inputRequirements) // 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() } @@ -2226,34 +2432,30 @@ public class ProgramBuilder { } // Todo, the context graph could also find ideal paths that allow type creation. - private func createRequiredInputVariables(forTypes types: Set) { - for type in types { - if type.Is(.jsAnything) && context.contains(.javascript) { - let _ = findOrGenerateType(type) - } else { - if type.Is(.wasmAnything) && context.contains(.wasmFunction) { - // Check if we can produce it with findOrGenerateWasmVar - let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) - } - if randomVariable(ofType: type) == 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 { - $0.Is(type) - } - } + private func createRequiredInputVariables(for requirements: Set) { + for requirement in requirements { + let type = requirement.type - // Cannot build type here. - if usableGenerators.isEmpty { - // Continue here though, as we might be able to create Variables for other types. - continue - } + if type.Is(.wasmAnything) && context.contains(.wasmFunction) { + // Check if we can produce it with findOrGenerateWasmVar + let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) + } + if findVariable(satisfying: { requirement.fulfilled(by: self.type(of: $0)) }) == nil { - let generator = usableGenerators.randomElement() + // 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) + } - let _ = complete(generator: generator, withBudget: 5) + // Cannot build type here. + if usableGenerators.isEmpty { + // Continue here though, as we might be able to create Variables for other types. + continue } + + let generator = usableGenerators.randomElement() + let _ = complete(generator: generator, withBudget: 5) } } } @@ -2272,7 +2474,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 } @@ -2280,7 +2484,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 } @@ -2333,8 +2539,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 { @@ -2355,18 +2563,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.types.map(randomVariable(forUseAs:)) + inputs = generator.inputs.constraints.map { randomVariable(forUseAs: $0.type) } case .strict: // Find inputs of the required type using randomVariable(ofType:) - for inputType in generator.inputs.types { - guard let input = randomVariable(ofType: inputType) else { + for requirement in generator.inputs.constraints { + 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 \(inputType).") + buildLog?.reportFailure( + reason: + "Cannot find variable that satifies input constraints \(requirement.type)." + ) return 0 } inputs.append(input) @@ -2379,9 +2593,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.") } @@ -2403,7 +2617,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!") } @@ -2413,7 +2629,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.. 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 @@ -2463,6 +2683,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) } @@ -2521,7 +2745,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) { @@ -2549,35 +2775,62 @@ public class ProgramBuilder { b.emit(ObjectLiteralSetPrototype(), withInputs: [proto]) } - public func addMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addMethod( + _ 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)) + let instr = b.emit( + 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]) -> ()) { + public func addComputedMethod( + _ 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]) + let instr = b.emit( + BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), + withInputs: [name] + defaultValues) 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 addSetter(for name: String, _ body: (_ this: Variable, _ val: 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) -> 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) -> Void + ) { + let instr = b.emit(BeginObjectLiteralComputedSetter(), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndObjectLiteralComputedSetter()) + } } @discardableResult - public func buildObjectLiteral(_ body: (ObjectLiteral) -> ()) -> Variable { + public func buildObjectLiteral(_ body: (ObjectLiteral) -> Void) -> Variable { emit(BeginObjectLiteral()) body(currentObjectLiteral) return emit(EndObjectLiteral()).output @@ -2608,7 +2861,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] = [] @@ -2616,7 +2871,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: @@ -2637,140 +2894,242 @@ public class ProgramBuilder { self.isDerivedClass = isDerived } - public func addConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addConstructor( + 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()) } 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]) -> ()) { + public func addInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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), + withInputs: defaultValues) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) } - public func addInstanceComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addInstanceComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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] + defaultValues) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) + } + + 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 addInstanceGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceGetter(propertyName: name)) + public func addInstanceComputedGetter( + for name: Variable, _ body: (_ this: Variable) -> Void + ) { + let instr = b.emit(BeginClassComputedGetter(isStatic: false), withInputs: [name]) body(instr.innerOutput) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassComputedGetter()) + } + + 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 addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceSetter(propertyName: name)) + 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(EndClassInstanceSetter()) + b.emit(EndClassComputedSetter()) } 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) -> ()) { + 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, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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), + withInputs: defaultValues) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) } - public func addStaticComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addStaticComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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] + defaultValues) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) + } + + 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 addStaticGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassStaticGetter(propertyName: name)) + public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> Void) + { + let instr = b.emit(BeginClassComputedGetter(isStatic: true), withInputs: [name]) body(instr.innerOutput) - b.emit(EndClassStaticGetter()) + b.emit(EndClassComputedGetter()) + } + + 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 addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassStaticSetter(propertyName: name)) + 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(EndClassStaticSetter()) + b.emit(EndClassComputedSetter()) } 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]) -> ()) { + public func addPrivateInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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), + withInputs: defaultValues) 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]) -> ()) { + public func addPrivateStaticMethod( + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) 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), + withInputs: defaultValues) body(Array(instr.innerOutputs)) - b.emit(EndClassPrivateStaticMethod()) + 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 - if enableRecursionGuard { hide(output) } - body(currentClassDefinition) - if enableRecursionGuard { unhide(output) } + let output = emit( + BeginClassDefinition(hasSuperclass: superclass != nil, isExpression: isExpression), + withInputs: inputs + ).output + bodyWithRecursionGuard(output) { body(currentClassDefinition) } emit(EndClassDefinition()) return output } @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 @@ -2790,25 +3149,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 } @@ -2819,21 +3189,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 } @@ -2841,30 +3224,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 } @@ -2872,25 +3272,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]) } } @@ -2916,7 +3331,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) { @@ -2924,8 +3341,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 } @@ -2947,8 +3370,46 @@ 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, defaultParameterIndices: [Int] = [] + ) -> SubroutineDescriptor { + return SubroutineDescriptor( + 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 { @@ -2956,97 +3417,130 @@ 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, + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) + 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, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndArrowFunction()) return instr.output } @discardableResult - public func buildGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) + 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, + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) + 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, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginAsyncArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncArrowFunction()) return instr.output } @discardableResult - public func buildAsyncGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginAsyncGeneratorFunction( + parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) + 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, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void + ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginConstructor(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + let instr = emit( + BeginConstructor(parameters: descriptor.parameters), withInputs: defaultValues) + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndConstructor()) return instr.output } @@ -3088,36 +3582,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 @@ -3127,18 +3658,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 @@ -3156,8 +3703,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 @@ -3165,40 +3712,64 @@ 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 - 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 @@ -3207,12 +3778,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 } @@ -3226,8 +3800,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 } @@ -3247,7 +3825,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 @@ -3259,13 +3839,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 @@ -3286,7 +3873,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]) } @@ -3313,20 +3901,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()) @@ -3353,12 +3941,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) @@ -3366,7 +3959,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)) @@ -3379,43 +3975,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()) @@ -3429,8 +4038,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 { @@ -3448,7 +4062,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()) @@ -3461,11 +4075,20 @@ 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]) } - @discardableResult public func createWasmGlobal(value: WasmGlobal, isMutable: Bool) -> Variable { let variable = emit(CreateWasmGlobal(value: value, isMutable: isMutable)).output @@ -3473,13 +4096,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 @@ -3506,11 +4136,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 @@ -3526,7 +4159,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)) @@ -3544,43 +4177,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 @@ -3594,23 +4251,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 @@ -3620,37 +4297,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 @@ -3660,12 +4351,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 @@ -3720,101 +4415,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(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 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(signature: signature), - 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(signature: signature), + 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? { - let instr = b.emit(WasmJsCall(signature: signature), withInputs: [function] + args, - types: [.function() | .object(ofGroup: "WasmSuspendingObject")] + signature.parameterTypes) + 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) if signature.outputTypes.isEmpty { assert(!instr.hasOutputs) return nil @@ -3825,78 +4576,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) { @@ -3904,246 +4709,419 @@ public class ProgramBuilder { } public func wasmDropElementSegment(elementSegment: Variable) { - b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) + b.emit( + WasmDropElementSegment(), withInputs: [elementSegment], + types: [.wasmElementSegment()]) } - public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { - let elementSegmentType = ILType.wasmFuncRef + // TODO(pawkra): support shared tables and element segments. + 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) { - assert(b.type(of: variable) == b.type(of: to)) - b.emit(WasmReassign(variableType: b.type(of: variable)), withInputs: [variable, to]) - } - - public enum wasmBlockType { - case typeIdx(Int) - case valueType(ILType) + assert(b.type(of: to).Is(b.type(of: variable))) + b.emit(WasmReassign(), withInputs: [variable, to]) } // 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 instr = b.emit(WasmBeginBlock(with: signature), withInputs: args, types: signature.parameterTypes) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + let instr = b.emit( + WasmBeginBlock(parameterCount: signature.parameterTypes.count), + withInputs: [signatureDef] + args, + types: [.wasmTypeDef()] + signature.parameterTypes) body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - b.emit(WasmEndBlock(outputTypes: [])) + b.emit(WasmEndBlock(outputCount: 0), withInputs: [signatureDef]) } @discardableResult - public func wasmBuildBlockWithResults(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - let instr = b.emit(WasmBeginBlock(with: signature), withInputs: args, types: signature.parameterTypes) + 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(outputTypes: signature.outputTypes), withInputs: results, types: signature.outputTypes).outputs) - } - - // Convenience function to begin a wasm block. Note that this does not emit an end block. - func wasmBeginBlock(with signature: WasmSignature, args: [Variable]) { - b.emit(WasmBeginBlock(with: signature), withInputs: args, types: signature.parameterTypes) - } - // Convenience function to end a wasm block. - func wasmEndBlock(outputTypes: [ILType], args: [Variable]) { - b.emit(WasmEndBlock(outputTypes: outputTypes), withInputs: args, types: outputTypes) + 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(labelTypes: labelType.wasmLabelType!.parameters), 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)) - b.emit(WasmBranchIf(labelTypes: labelType.wasmLabelType!.parameters, hint: hint), withInputs: [label] + args + [condition]) + b.emit( + WasmBranchIf(parameterCount: labelType.wasmLabelType!.parameters.count, hint: hint), + withInputs: [label] + args + [condition]) } public func wasmBranchTable(on: Variable, labels: [Variable], args: [Variable]) { - let argumentTypes = args.map({b.type(of: $0)}) - labels.forEach { - checkArgumentsMatchLabelType(label: b.type(of: $0), args: args) - } - b.emit(WasmBranchTable(labelTypes: argumentTypes, valueCount: labels.count - 1), + labels.forEach { checkArgumentsMatchLabelType(label: b.type(of: $0), args: args) } + b.emit( + WasmBranchTable(parameterCount: args.count, valueCount: labels.count - 1), withInputs: labels + args + [on]) } - public func wasmBuildIfElse(_ condition: Variable, hint: WasmBranchHint = .None, ifBody: () -> Void, elseBody: (() -> Void)? = nil) { - b.emit(WasmBeginIf(hint: hint), withInputs: [condition]) - ifBody() - if let elseBody { - b.emit(WasmBeginElse()) - elseBody() - } - b.emit(WasmEndIf()) - } - - public func wasmBuildIfElse(_ condition: Variable, signature: WasmSignature, args: [Variable], inverted: Bool, ifBody: (Variable, [Variable]) -> Void, elseBody: ((Variable, [Variable]) -> Void)? = nil) { - let beginBlock = b.emit(WasmBeginIf(with: signature, inverted: inverted), - withInputs: args + [condition], - types: signature.parameterTypes + [.wasmi32]) + 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), + 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(with: signature)) + 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...))) } - b.emit(WasmEndIf()) + b.emit(WasmEndIf(), withInputs: [signatureDef], types: [.wasmTypeDef()]) } + // 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] { - let beginBlock = b.emit(WasmBeginIf(with: signature, hint: hint), withInputs: args + [condition], types: signature.parameterTypes + [.wasmi32]) - let trueResults = ifBody(beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) - let elseBlock = b.emit(WasmBeginElse(with: signature), withInputs: trueResults, types: signature.outputTypes) - let falseResults = elseBody(elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) - return Array(b.emit(WasmEndIf(outputTypes: signature.outputTypes), withInputs: falseResults, types: signature.outputTypes).outputs) + 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 elseBlock = b.emit( + 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) } - // The first output of this block is a label variable, which is just there to explicitly mark control-flow and allow branches. - public func wasmBuildLoop(with signature: WasmSignature, body: (Variable, [Variable]) -> Void) { - let instr = b.emit(WasmBeginLoop(with: signature)) - body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - b.emit(WasmEndLoop()) + @discardableResult + 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) } + // TODO(mliedtke): Also use this inside the code generator. @discardableResult - public func wasmBuildLoop(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - let instr = b.emit(WasmBeginLoop(with: signature), withInputs: args, types: signature.parameterTypes) + 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) + } + + 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(outputTypes: signature.outputTypes), withInputs: fallthroughResults, types: 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) -> Void = { labelType in + assert(labelType.Is(.anyWasmLabel)) + assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef())) + } for catchKind in catches { switch catchKind { case .Ref: assert(b.type(of: args[argIndex]).Is(.object(ofGroup: "WasmTag"))) let labelType = b.type(of: args[argIndex + 1]) - assert(labelType.Is(.anyLabel)) - assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef)) + assertLabelTypeData(labelType) 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]) - assert(labelType.Is(.anyLabel)) - assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef)) + assertLabelTypeData(labelType) argIndex += 1 case .AllNoRef: - assert(b.type(of: args[argIndex]).Is(.anyLabel)) + assert(b.type(of: args[argIndex]).Is(.anyWasmLabel)) argIndex += 1 } } #endif - let instr = b.emit(WasmBeginTryTable(with: signature, catches: catches), withInputs: args) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + let instr = b.emit( + 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(outputTypes: signature.outputTypes), withInputs: 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 + ) { + 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 => []) + } - public func wasmBuildLegacyTry(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, catchAllBody: ((Variable) -> Void)? = nil) { - let instr = b.emit(WasmBeginTry(with: signature), withInputs: args, types: signature.parameterTypes) - body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - if let catchAllBody = catchAllBody { - let instr = b.emit(WasmBeginCatchAll(inputTypes: signature.outputTypes)) + 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))." + ) + let tagSignatureDef = tagSignatures[i] + let instr = b.emit( + WasmBeginCatch( + blockOutputCount: signature.outputTypes.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...))) + } + if let catchAllBody { + let instr = b.emit( + WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef]) catchAllBody(instr.innerOutput(0)) } - b.emit(WasmEndTry()) + b.emit(WasmEndTry(blockOutputCount: 0), withInputs: [signatureDef]) } // The catchClauses expect a list of (tag, block-generator lambda). // The lambda's inputs are the block label, the exception label (for rethrowing) and the // tag arguments. @discardableResult - public func wasmBuildLegacyTryWithResult(with signature: WasmSignature, args: [Variable], - body: (Variable, [Variable]) -> [Variable], - catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])], - catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] { - let instr = b.emit(WasmBeginTry(with: signature), withInputs: args, types: signature.parameterTypes) + 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] { + 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 { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") - let instr = b.emit(WasmBeginCatch(with: b.type(of: tag).wasmTagType!.parameters => signature.outputTypes), - withInputs: [tag] + result, - types: [.object(ofGroup: "WasmTag")] + signature.outputTypes) - result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + 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, 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 { - let instr = b.emit(WasmBeginCatchAll(inputTypes: signature.outputTypes), withInputs: result, types: signature.outputTypes) + 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(outputTypes: signature.outputTypes), withInputs: result, types: signature.outputTypes).outputs) - } - - // Build a legacy catch block without a result type. Note that this may only be placed into - // try blocks that also don't have a result type. (Use wasmBuildLegacyTryWithResult to - // create a catch block with a result value.) - public func WasmBuildLegacyCatch(tag: Variable, body: ((Variable, Variable, [Variable]) -> Void)) { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") - let instr = b.emit(WasmBeginCatch(with: b.type(of: tag).wasmTagType!.parameters => []), withInputs: [tag], types: [.object(ofGroup: "WasmTag")]) - body(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + 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(parameterTypes: tagType.parameters), 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) { - b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef]) + 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(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 instr = b.emit(WasmBeginTryDelegate(with: signature), withInputs: args, types: signature.parameterTypes) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + let instr = b.emit( + WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), + withInputs: [signatureDef] + args, + types: [.wasmTypeDef()] + signature.parameterTypes) body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - b.emit(WasmEndTryDelegate(), withInputs: [delegate]) + b.emit(WasmEndTryDelegate(outputCount: 0), withInputs: [signatureDef, delegate]) } @discardableResult - public func wasmBuildLegacyTryDelegateWithResult(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable], delegate: Variable) -> [Variable] { - let instr = b.emit(WasmBeginTryDelegate(with: signature), withInputs: args, types: signature.parameterTypes) + 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), + withInputs: [signatureDef] + args, + types: [.wasmTypeDef()] + signature.parameterTypes) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndTryDelegate(outputTypes: signature.outputTypes), - withInputs: [delegate] + results, - types: [.anyLabel] + signature.outputTypes - ).outputs) + return Array( + b.emit( + WasmEndTryDelegate(outputCount: signature.outputTypes.count), + withInputs: [signatureDef, delegate] + results, + types: [.wasmTypeDef(), .anyWasmLabel] + signature.outputTypes + ).outputs) } public func generateRandomWasmVar(ofType type: ILType) -> Variable? { @@ -4157,34 +5135,45 @@ 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 // code generation in other contexts? switch type.wasmReferenceType?.kind { - case .Abstract(let heapType): - if heapType == .WasmI31 { - // Prefer generating a non-null value. - return probability(0.2) && type.wasmReferenceType!.nullability - ? self.wasmRefNull(type: type) - : self.wasmRefI31(self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) + case .Abstract(let heapTypeInfo): + // TODO(pawkra): add support for shared refs. + assert(!heapTypeInfo.shared) + if probability(0.2) && type.wasmReferenceType!.nullability { + return self.wasmRefNull(type: type) + } + // Prefer generating a non-null value. + if heapTypeInfo.heapType == .WasmI31 { + return self.wasmRefI31( + self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) + } + // TODO(pawkra): support other non-nullable types. + if type.wasmReferenceType!.nullability { + return self.wasmRefNull(type: type) + } + case .Index(_): + if type.wasmReferenceType?.nullability ?? false { + return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) } - assert(type.wasmReferenceType!.nullability) - return self.wasmRefNull(type: type) - case .Index(_), - .none: - break // Unimplemented + case .none: + break } - } else { - return nil } return nil } } public func findOrGenerateWasmVar(ofType type: ILType) -> Variable { - b.randomVariable(ofType: type) ?? generateRandomWasmVar(ofType: type)! + if let result = b.randomVariable(ofType: type) ?? generateRandomWasmVar(ofType: type) { + return result + } + fatalError("Could not find or generate wasm variable of type \(type)") } public func wasmUnreachable() { @@ -4192,23 +5181,31 @@ 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(returnTypes: values.map(b.type)), withInputs: values, types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: values.count), withInputs: values, + types: signature.outputTypes) } public func wasmReturn(_ returnVariable: Variable) { - let returnType = b.type(of: returnVariable) - b.emit(WasmReturn(returnTypes: [returnType]), withInputs: [returnVariable], types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: 1), withInputs: [returnVariable], + types: signature.outputTypes) } public func wasmReturn() { assert(signature.outputTypes.isEmpty) - b.emit(WasmReturn(returnTypes: []), withInputs: []) + b.emit(WasmReturn(returnCount: 0), withInputs: []) } @discardableResult @@ -4217,45 +5214,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 @@ -4264,47 +5303,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 @@ -4318,16 +5382,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 } @discardableResult @@ -4336,12 +5412,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]) } @@ -4349,7 +5430,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 } @@ -4364,24 +5446,54 @@ public class ProgramBuilder { } @discardableResult - public func wasmRefI31(_ number: Variable) -> Variable { - return b.emit(WasmRefI31(), withInputs: [number], types: [.wasmi32]).output + // TODO(pawkra): Support shared references. + public func wasmRefEq(_ lhs: Variable, _ rhs: Variable) -> Variable { + 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 } @discardableResult public func wasmI31Get(_ refI31: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31], types: [.wasmI31Ref]).output + return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31]).output } @discardableResult public func wasmAnyConvertExtern(_ ref: Variable) -> Variable { - b.emit(WasmAnyConvertExtern(), withInputs: [ref], types: [.wasmExternRef]).output + b.emit(WasmAnyConvertExtern(), withInputs: [ref]).output } @discardableResult public func wasmExternConvertAny(_ ref: Variable) -> Variable { - b.emit(WasmExternConvertAny(), withInputs: [ref], types: [.wasmAnyRef]).output + b.emit(WasmExternConvertAny(), withInputs: [ref]).output + } + + @discardableResult + 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()] + return b.emit(WasmRefTest(refType: refType), withInputs: inputs, types: types).output + } + + @discardableResult + 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()] + return b.emit(WasmRefCast(refType: refType), withInputs: inputs, types: types).output } + } public class WasmModule { @@ -4429,10 +5541,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 { - let instr = b.emit(BeginWasmFunction(signature: signature)) - let results = body(currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return b.emit(EndWasmFunction(signature: signature), withInputs: results).output + 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 { + 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 } @discardableResult @@ -4441,33 +5572,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 @@ -4475,9 +5627,16 @@ public class ProgramBuilder { return b.emit(WasmDefineDataSegment(segment: segment)).output } + @discardableResult + public func addTag(signature: Variable) -> Variable { + return b.emit(WasmDefineTag(), withInputs: [signature]).output + } + + // Convenience function to create a tag including an adhoc signature definition. @discardableResult public func addTag(parameterTypes: [ILType]) -> Variable { - return b.emit(WasmDefineTag(parameterTypes: parameterTypes)).output + let signatureDef = b.wasmDefineAdHocSignatureType(signature: parameterTypes => []) + return addTag(signature: signatureDef) } private func getModuleVariable() -> Variable { @@ -4506,7 +5665,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) @@ -4520,7 +5681,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. @@ -4529,77 +5691,151 @@ public class ProgramBuilder { return (dynamicOffset, alignedStaticOffset) } + func generateRandomWasmStructFields() -> ( + fields: [WasmStructTypeDescription.Field], indexTypes: [Variable] + ) { + var indexTypes: [Variable] = [] + + let fields = (0.. WasmGlobal { + // TODO(pawkra): enable shared element types. switch context { case .javascript: // These are valid in JS according to: https://webassembly.github.io/spec/js-api/#globals. // TODO: add simd128 and anyfunc. return withEqualProbability( - {.wasmf32(Float32(self.randomFloat()))}, - {.wasmf64(self.randomFloat())}, - {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, - {.wasmi64(self.randomInt())}, - {.externref}) + { .wasmf32(Float32(self.randomFloat())) }, + { .wasmf64(self.randomFloat()) }, + { .wasmi32(Int32(truncatingIfNeeded: self.randomInt())) }, + { .wasmi64(self.randomInt()) }, + { .externref }) case .wasm: // TODO: Add simd128 and nullrefs. return withEqualProbability( - {.wasmf32(Float32(self.randomFloat()))}, - {.wasmf64(self.randomFloat())}, - {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, - {.wasmi64(self.randomInt())}, - {.externref}, - {.exnref}, - {.i31ref}) + { .wasmf32(Float32(self.randomFloat())) }, + { .wasmf64(self.randomFloat()) }, + { .wasmi32(Int32(truncatingIfNeeded: self.randomInt())) }, + { .wasmi64(self.randomInt()) }, + { .externref }, + { .exnref }, + { .i31ref }) default: fatalError("Unsupported context \(context) for a WasmGlobal.") } } - public func randomTagParameters() -> [ILType] { + // Random tag parameters for Wasm tags defined via the JS API + public func randomTagParametersJs() -> [ILType] { // TODO(mliedtke): The list of types should be shared with function signature generation // etc. We should also support non-nullable references but that requires being able // to generate valid ones which currently isn't the case for most of them. - return (0.. WasmSignature { // TODO: generalize this to support more types. Also add support for simd128 and // (null)exnref, note however that these types raise exceptions when used from JS. + // TODO(pawkra): enable shared types. let valueTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64] - let abstractRefTypes: [ILType] = [.wasmExternRef, .wasmAnyRef, .wasmI31Ref] - let nullTypes: [ILType] = [.wasmNullRef, .wasmNullExternRef, .wasmNullFuncRef] + let abstractRefTypes: [ILType] = [.wasmExternRef(), .wasmAnyRef(), .wasmI31Ref()] + let nullTypes: [ILType] = [.wasmNullRef(), .wasmNullExternRef(), .wasmNullFuncRef()] let randomType = { 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]) + { + let typeCount = Int.random(in: 0...10) + let returnCount = withResults ? Int.random(in: 0...typeCount) : 0 + let parameterCount = typeCount - returnCount + + var indexTypes: [Variable] = [] + let chooseType = { + if let elementType = self.randomVariable(ofType: .wasmTypeDef()), probability(0.25) { + 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) + }) + } + } + let signature = + (0.. (0.. [ILType] { // TODO(mliedtke): This should allow more types as well as non-nullable references for all // abstract heap types. To be able to emit them, generateRandomWasmVar() needs to be able // to generate a sequence that produces such a non-nullable value which might be difficult // for some types as of now. - (0.. [Variable] { - (0.. [Variable] { + (0.. WasmBranchHint { @@ -4612,10 +5848,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)) } @@ -4623,7 +5861,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) @@ -4640,9 +5878,14 @@ public class ProgramBuilder { } @discardableResult - public func wasmDefineTypeGroup(recursiveGenerator: () -> ()) -> [Variable] { + public func wasmDefineTypeGroup(recursiveGenerator: () -> Void) -> [Variable] { emit(WasmBeginTypeGroup()) recursiveGenerator() + return wasmEndTypeGroup() + } + + @discardableResult + public func wasmEndTypeGroup() -> [Variable] { // Make all type definitions visible. let types = scopes.top.filter { let t = type(of: $0) @@ -4656,14 +5899,53 @@ public class ProgramBuilder { return emit(WasmDefineSignatureType(signature: signature), withInputs: indexTypes).output } + /// Like wasmDefineSignatureType but instead of within a type group this defines a signature + /// type directly inside a wasm function or wasm module. + /// 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 + type.Is(.anyIndexRef) + ? .wasmRef(.Index(), nullability: type.wasmReferenceType!.nullability) + : type + } + let signature = + signature.parameterTypes.map(cleanIndexTypes) + => signature.outputTypes.map(cleanIndexTypes) + if context.contains(.wasmFunction) { + return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes) + .output + } else { + assert(context.contains(.wasm)) + 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 } @@ -4678,20 +5960,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)) @@ -4779,12 +6066,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: + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter: break case .endObjectLiteral: activeObjectLiterals.pop() @@ -4793,41 +6086,63 @@ 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 .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 .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): activeClassDefinitions.top.privateMethods.append(op.methodName) case .beginClassStaticInitializer: break @@ -4855,51 +6170,23 @@ 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(let op): - activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) - case .wasmBeginIf(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmBeginBlock(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmBeginLoop(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmBeginTry(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmBeginTryDelegate(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmBeginTryTable(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmEndIf(_), - .wasmEndLoop(_), - .wasmEndTry(_), - .wasmEndTryDelegate(_), - .wasmEndTryTable(_), - .wasmEndBlock(_): - activeWasmModule!.blockSignatures.pop() - case .beginPlainFunction(_), - .beginArrowFunction(_), - .beginAsyncArrowFunction(_), - .beginAsyncFunction(_), - .beginAsyncGeneratorFunction(_), - .beginCodeString(_), - .beginGeneratorFunction(_): - assert(instr.numOutputs == 1) - lastFunctionVariables.push(instr.output) - case .endPlainFunction(_), - .endArrowFunction(_), - .endAsyncArrowFunction(_), - .endAsyncFunction(_), - .endAsyncGeneratorFunction(_), - .endCodeString(_), - .endGeneratorFunction(_): - lastFunctionVariables.pop() + case .beginWasmFunction(_): + activeWasmModule!.functions.append( + WasmFunction(forBuilder: self, signatureDef: instr.input(0))) + case .wasmBeginTry(_), + .wasmEndTryDelegate(_), + .wasmBeginTryDelegate(_), + .wasmBeginTryTable(_), + .wasmEndTryTable(_), + .wasmDefineAdHocModuleSignatureType(_): + break default: assert(!instr.op.requiredContext.contains(.objectLiteral)) @@ -4914,31 +6201,47 @@ public class ProgramBuilder { // so we instead register a generator that allows the fuzzer a greater chance of generating // one when needed. // - // These can be registered on the JavaScriptEnvironment with addProducingGenerator() + // These can be registered on the JavaScriptEnvironment with addProducingGenerator(). + // argument `predefined`: Provide values that should be used for the given properties of the + // options bag (if present) instead of finding or generating random values for them. The + // property might still be filtered out. @discardableResult - func createOptionsBag(_ bag: OptionsBag) -> Variable { + 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] = bag.properties.filter {_ in probability(0.8)}.mapValues { - if $0.isEnumeration { - return loadEnum($0) - // relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it - } else if $0.Is(OptionsBag.jsTemporalRelativeTo) { - return findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime, - .jsTemporalPlainDate, .string])) - } else { - return findOrGenerateType($0) - } - } + 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) } @@ -4949,7 +6252,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 @@ -4964,7 +6268,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 @@ -4973,13 +6279,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 @@ -4991,8 +6297,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 @@ -5006,7 +6314,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!) } @@ -5016,7 +6325,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 @@ -5024,7 +6333,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": @@ -5044,12 +6354,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. @@ -5058,7 +6368,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)) @@ -5109,7 +6419,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) @@ -5164,20 +6474,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) @@ -5186,12 +6498,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) @@ -5202,7 +6516,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? @@ -5213,9 +6530,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() { @@ -5227,9 +6547,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() { @@ -5242,9 +6565,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)) } @@ -5253,7 +6579,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 @@ -5267,7 +6596,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)] @@ -5280,12 +6612,75 @@ public class ProgramBuilder { @discardableResult static func constructIntlLocaleString() -> String { + // TODO(Manishearth) Generate more complicated locale strings, not just language strings + return constructIntlLanguageString() + } + + @discardableResult + static func constructIntlLanguageString() -> String { // TODO(Manishearth) Generate more interesting locales than just the builtins return chooseUniform(from: Locale.availableIdentifiers) } // 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 allAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + fileprivate static let allAlphaNum = allAlpha + "0123456789" + fileprivate static let allRegionsTwoDigit = [ + "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", + "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", + "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", + "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", + "CO", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", + "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", + "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", + "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", + "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", + "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", + "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", + "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", + "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", + "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", + "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", + "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", + "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", + "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", + "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", + "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", + "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW", + ] @discardableResult static func constructIntlUnit() -> String { @@ -5298,6 +6693,59 @@ public class ProgramBuilder { } } + @discardableResult + static func constructIntlScriptString() -> String { + if probability(0.7) { + return chooseUniform(from: allScripts) + } else { + return String((0..<4).map { _ in allAlpha.randomElement()! }) + } + } + + @discardableResult + static func constructIntlRegionString() -> String { + // either two letters or three digits + if probability(0.5) { + return allRegionsTwoDigit.randomElement()! + } else { + return String(format: "%03d", Int.random(in: 0...999)) + } + } + + @discardableResult + private static func constructSingleIntlVariantString() -> String { + // 5-8 alphanumerics or a digit and 3 alphanumerics + if probability(0.5) { + let count = Int.random(in: 5...8) + return String((0.. String { + if probability(0.9) { + return constructSingleIntlVariantString() + } else { + return "\(constructSingleIntlVariantString())-\(constructIntlVariantString())" + } + } + + @discardableResult + func constructIntlLocale() -> Variable { + let intl = createNamedVariable(forBuiltin: "Intl") + let constructor = getProperty("Locale", of: intl) + + var args: [Variable] = [] + args.append(findOrGenerateType(.jsIntlLocaleString)) + if probability(0.7) { + args.append(createOptionsBag(.jsIntlLocaleSettings)) + } + return construct(constructor, withArgs: args) + } + // Generic generators for Intl types. private func constructIntlType(type: String, optionsBag: OptionsBag) -> Variable { let intl = createNamedVariable(forBuiltin: "Intl") @@ -5324,6 +6772,11 @@ public class ProgramBuilder { return constructIntlType(type: "Collator", optionsBag: .jsIntlCollatorSettings) } + @discardableResult + func constructIntlDisplayNames() -> Variable { + return constructIntlType(type: "DisplayNames", optionsBag: .jsIntlDisplayNamesSettings) + } + @discardableResult func constructIntlListFormat() -> Variable { return constructIntlType(type: "ListFormat", optionsBag: .jsIntlListFormatSettings) @@ -5341,12 +6794,49 @@ public class ProgramBuilder { @discardableResult func constructIntlRelativeTimeFormat() -> Variable { - return constructIntlType(type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) + return constructIntlType( + type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) } @discardableResult func constructIntlSegmenter() -> Variable { return constructIntlType(type: "Segmenter", optionsBag: .jsIntlSegmenterSettings) } -} + // Fuzz calls with the pattern new Intl.DisplayNames(locale, settings).of(code). + // These need to be generated together as there is a tight coupling between the `type` property + // in the settings optionsbag and the valid code values passed to the `of` method. + @discardableResult + func fuzzIntlDisplayNamesOf() -> Variable { + let intl = createNamedVariable(forBuiltin: "Intl") + let ctor = getProperty("DisplayNames", of: intl) + let types = fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues + let type = types.randomElement()! + let locale = loadString(ProgramBuilder.constructIntlLocaleString()) + let options = createOptionsBag( + .jsIntlDisplayNamesSettings, + predefined: ["type": loadString(type)]) + construct(ctor, withArgs: [locale, options]) + let code = + switch type { + case "language": + ProgramBuilder.constructIntlLanguageString() + case "region": + ProgramBuilder.constructIntlRegionString() + case "script": + ProgramBuilder.constructIntlScriptString() + case "currency": + Locale.commonISOCurrencyCodes.randomElement()! + case "calendar": + fuzzer.environment.getEnum(ofName: "temporalCalendar")!.enumValues.randomElement()! + case "dateTimeField": + [ + "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 07be36f35..e4d7dfc7f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -17,18 +17,8 @@ protocol GeneratorAdapter { func run(in b: ProgramBuilder, with inputs: [Variable]) } -public typealias ValueGeneratorFunc = (ProgramBuilder, Int) -> () -fileprivate struct ValueGeneratorAdapter: GeneratorAdapter { - let expectedNumberOfInputs = 0 - let f: ValueGeneratorFunc - func run(in b: ProgramBuilder, with inputs: [Variable]) { - assert(inputs.isEmpty) - f(b, GeneratorStub.numberOfValuesToGenerateByValueGenerators) - } -} - -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]) { @@ -37,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]) { @@ -47,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]) { @@ -57,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]) { @@ -67,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]) { @@ -88,6 +79,62 @@ public class GeneratorStub: Contributor { /// How many different values of the same type ValueGenerators should aim to generate. public static let numberOfValuesToGenerateByValueGenerators = 3 + public enum AdditionalConstraints { + case None + case IsWasmArray + case IsWasmStruct + case IsWasmFunction // On a type definition this means "signature". + } + + public struct Constraint: Hashable { + let type: ILType + let additional: AdditionalConstraints + + public init(_ type: ILType, _ additional: AdditionalConstraints = .None) { + self.type = type + self.additional = additional + } + + public func fulfilled(by type: ILType) -> Bool { + if !type.Is(self.type) { + 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 + } + } + } + + public func fulfilled(by other: Constraint) -> Bool { + other.type.Is(self.type) + && (self.additional == .None || self.additional == other.additional) + } + } + /// Describes the inputs expected by a CodeGenerator. public struct Inputs { /// How the inputs should be treated. @@ -102,64 +149,71 @@ public class GeneratorStub: Contributor { case strict } - public let types: [ILType] + public let constraints: [Constraint] public let mode: Mode public var count: Int { - return types.count + return constraints.count } public var isEmpty: Bool { - types.count == 0 + constraints.count == 0 } // No inputs. public static var none: Inputs { - return Inputs(types: [], mode: .loose) + return Inputs(constraints: [], mode: .loose) } // One input of type .jsAnything public static var one: Inputs { - return Inputs(types: [.jsAnything], mode: .loose) + return Inputs(constraints: [.init(.jsAnything)], mode: .loose) } // One input of a wasmPrimitive and it has to be strict to ensure type correctness. public static var oneWasmPrimitive: Inputs { - return Inputs(types: [.wasmPrimitive], mode: .strict) + return Inputs(constraints: [.init(.wasmPrimitive)], mode: .strict) } public static var oneWasmNumericalPrimitive: Inputs { - return Inputs(types: [.wasmNumericalPrimitive], mode: .strict) + return Inputs(constraints: [.init(.wasmNumericalPrimitive)], mode: .strict) } // Two inputs of type .jsAnything public static var two: Inputs { - return Inputs(types: [.jsAnything, .jsAnything], mode: .loose) + let jsAny = Constraint(.jsAnything) + return Inputs(constraints: [jsAny, jsAny], mode: .loose) } // Three inputs of type .jsAnything public static var three: Inputs { - return Inputs(types: [.jsAnything, .jsAnything, .jsAnything], mode: .loose) + let jsAny = Constraint(.jsAnything) + return Inputs(constraints: [jsAny, jsAny, jsAny], mode: .loose) } // Four inputs of type .jsAnything public static var four: Inputs { - return Inputs(types: [.jsAnything, .jsAnything, .jsAnything, .jsAnything], mode: .loose) + let jsAny = Constraint(.jsAnything) + 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(types: types, 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(types: types, mode: .strict) + return Inputs(constraints: types.map { Constraint($0) }, mode: .strict) + } + + public static func requiredComplex(_ constraints: Constraint...) -> Inputs { + assert(!constraints.isEmpty) + return Inputs(constraints: constraints, mode: .strict) } } /// The inputs expected by this generator. @@ -167,7 +221,7 @@ public class GeneratorStub: Contributor { /// The types this CodeGenerator produces /// ProgramBuilding will assert that these types are (newly) available after running this CodeGenerator. - public let produces: [ILType] + public let produces: [Constraint] public enum ContextRequirement { // If this GeneratorStub has a single Context requirement, which may still be comprised of multiple Context values. @@ -177,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 } @@ -187,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) + }) } } @@ -214,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) + } } } } @@ -235,13 +293,16 @@ public class GeneratorStub: Contributor { public let requiredContext: ContextRequirement /// The context that is provided by running this Generator. - /// This is always a list of the single contexts that are provided, e.g. [.javascript] + /// This is always a list of the single contexts that are provided, e.g. [.javascript]. public let providedContext: [Context] - /// Warpper around the actual generator function called. + /// Wrapper around the actual generator function called. private let adapter: GeneratorAdapter - fileprivate init(name: String, inputs: Inputs, produces: [ILType] = [], 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 @@ -253,6 +314,15 @@ 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) + } + /// Execute this code generator, generating new code at the current position in the ProgramBuilder. /// Returns the number of generated instructions. public func run(in b: ProgramBuilder, with inputs: [Variable]) -> Int { @@ -265,28 +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), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + 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 + ) { 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)) } } @@ -297,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 @@ -316,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. @@ -330,7 +437,7 @@ public class CodeGenerator { // TODO(cffsmith): Maybe return an array of ILType Arrays, essentially describing at which yield point which type is available? // This would allow us to maybe use "innerOutputs" to find suitable points to insert other Generators (that require such types). // Slight complication is that some variables will only be in scope inside the CodeGenerator, e.g. if there is an EndWasmModule somewhere all Wasm variables will go out of scope. - public var produces: [ILType] { + public var produces: [GeneratorStub.Constraint] { return self.parts.last!.produces } @@ -343,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 { @@ -351,28 +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), + 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, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + 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: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) + 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) { + 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))]) + 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) { + 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))]) + 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) { + 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/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index c5e030303..f607ba62d 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 @@ -28,6 +29,8 @@ public let codeGeneratorWeights = [ "NamedVariableGenerator": 10, "ArrayGenerator": 10, "FloatArrayGenerator": 10, + "HoleyArrayGenerator": 10, + "ObjectIntegrityLevelGenerator": 1, "IntArrayGenerator": 10, "TypedArrayGenerator": 20, "BuiltinObjectInstanceGenerator": 10, @@ -47,8 +50,10 @@ public let codeGeneratorWeights = [ "BuiltinTemporalGenerator": 4, "BuiltinIntlGenerator": 4, "LoadNewTargetGenerator": 3, - "DisposableVariableGenerator": 5, - "AsyncDisposableVariableGenerator": 5, + "DisposableObjVariableGenerator": 3, + "DisposableClassVariableGenerator": 3, + "AsyncDisposableObjVariableGenerator": 3, + "AsyncDisposableClassVariableGenerator": 3, "HexGenerator": 2, "Base64Generator": 2, @@ -64,6 +69,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. @@ -87,11 +94,14 @@ public let codeGeneratorWeights = [ "ClassPrivateInstanceMethodGenerator": 5, "ClassPrivateStaticPropertyGenerator": 5, "ClassPrivateStaticMethodGenerator": 5, + "ClassComputedGetterGenerator": 3, + "ClassComputedSetterGenerator": 3, "ObjectWithSpreadGenerator": 2, "ArrayWithSpreadGenerator": 2, "TemplateStringGenerator": 1, + "ConcatenatedStringGenerator": 2, "StringNormalizeGenerator": 1, "PlainFunctionGenerator": 15, "StrictModeFunctionGenerator": 3, @@ -183,6 +193,7 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "TryFinallyGenerator": 5, "ThrowGenerator": 1, + "ConditionalThrowGenerator": 1, "BlockStatementGenerator": 1, // Special generators @@ -200,7 +211,12 @@ public let codeGeneratorWeights = [ "NumberComputationGenerator": 40, "ImitationGenerator": 30, "ResizableArrayBufferGenerator": 5, + "ResizableBufferResizeGenerator": 5, "GrowableSharedArrayBufferGenerator": 5, + "GrowableSharedBufferGrowGenerator": 5, + "TypedArrayFromBufferGenerator": 10, + "DataViewFromBufferGenerator": 5, + "TypedArrayLastIndexGenerator": 5, "FastToSlowPropertiesGenerator": 10, "IteratorGenerator": 5, "ConstructWithDifferentNewTargetGenerator": 5, @@ -209,13 +225,21 @@ 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, "WasmMemoryGenerator": 4, + "WasmMemoryToResizableBufferGenerator": 5, + "WasmMemoryToFixedLengthBufferGenerator": 5, + "WasmMemoryJSGrowGenerator": 5, "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, + // For generating bundles + // TODO(marja): Add modules. + "BundleScriptGenerator": 1, + // // Wasm generators // @@ -249,6 +273,7 @@ public let codeGeneratorWeights = [ "WasmGlobalLoadGenerator": 2, "WasmReassignmentGenerator": 2, "WasmDefineTagGenerator": 4, + "WasmAdHocModuleSignature": 2, // Primitive Value Generators "WasmLoadi32Generator": 4, @@ -306,10 +331,12 @@ public let codeGeneratorWeights = [ "WasmLoopGenerator": 8, "WasmLoopWithSignatureGenerator": 8, "WasmLegacyTryCatchGenerator": 8, - "WasmLegacyTryCatchWithResultGenerator": 8, "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, @@ -342,8 +369,10 @@ public let codeGeneratorWeights = [ // Wasm-gc type generators // These run in the javascript context and define types to be used within wasm modules. "WasmTypeGroupGenerator": 5, + "WasmTypeGroupWithAllTypesGenerator": 5, "WasmArrayTypeGenerator": 5, "WasmStructTypeGenerator": 5, + "WasmSignatureTypeGenerator": 5, "WasmSelfReferenceGenerator": 5, "WasmForwardReferenceGenerator": 5, @@ -352,13 +381,19 @@ public let codeGeneratorWeights = [ "WasmArrayLengthGenerator": 5, "WasmArrayGetGenerator": 5, "WasmArraySetGenerator": 5, + "WasmStructNewGenerator": 5, "WasmStructNewDefaultGenerator": 5, "WasmStructGetGenerator": 5, "WasmStructSetGenerator": 5, "WasmRefNullGenerator": 5, "WasmRefIsNullGenerator": 5, + "WasmRefEqGenerator": 5, "WasmRefI31Generator": 5, "WasmI31GetGenerator": 5, "WasmAnyConvertExternGenerator": 5, "WasmExternConvertAnyGenerator": 5, + "WasmRefTestGenerator": 5, + "WasmRefTestAbstractGenerator": 5, + "WasmRefCastGenerator": 5, + "WasmRefCastAbstractGenerator": 5, ] diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index c31dfab81..8bc94f6db 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Generator stubs for disposable and async-disposable variables. -func disposableVariableGeneratorStubs( - inContext contextRequirement : Context, - withSymbol symbolProperty : String, - genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { +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] { return [ GeneratorStub( "DisposableObjectLiteralBeginGenerator", @@ -24,7 +27,9 @@ func disposableVariableGeneratorStubs( provides: [.objectLiteral] ) { b in // Ensure we have the desired symbol below. - b.createSymbolProperty(symbolProperty) + let symbol = b.createSymbolProperty(symbolProperty) + b.hide(symbol) + b.runtimeData.push("symbol", symbol) b.emit(BeginObjectLiteral()) }, GeneratorStub( @@ -32,9 +37,7 @@ func disposableVariableGeneratorStubs( inContext: .single(.objectLiteral), provides: [.javascript, .subroutine, .method] ) { b in - // It should be safe to assume that we find at least the - // desired symbol we created above. - let symbol = b.randomVariable(forUseAs: .jsSymbol) + let symbol = b.runtimeData.pop("symbol") let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -60,6 +63,73 @@ func disposableVariableGeneratorStubs( ] } +// Generator stubs for disposable and async-disposable class variables. +func disposableClassVariableGeneratorStubs( + inContext contextRequirement: Context, + withSymbol symbolProperty: String, + genDisposableVariable: @escaping (ProgramBuilder, Variable) -> Void +) -> [GeneratorStub] { + return [ + GeneratorStub( + "DisposableClassDefinitionBeginGenerator", + inContext: .single(contextRequirement), + provides: [.classDefinition] + ) { b in + // Ensure we have the desired symbol below. + let symbol = b.createSymbolProperty(symbolProperty) + b.hide(symbol) + b.runtimeData.push("symbol", symbol) + + // Possibly pick a superclass. + // The superclass must be a constructor (or null). + var superclass: Variable? = nil + if probability(0.5) && b.hasVisibleVariables { + superclass = b.randomVariable(ofType: .constructor()) + } + let inputs = superclass != nil ? [superclass!] : [] + let cls = b.emit( + BeginClassDefinition( + hasSuperclass: superclass != nil, + isExpression: probability(0.3)), + withInputs: inputs + ).output + b.runtimeData.push("class", cls) + }, + GeneratorStub( + "DisposableClassInstanceComputedMethodBeginGenerator", + inContext: .single(.classDefinition), + provides: [.javascript, .subroutine, .method, .classMethod] + ) { b in + let symbol = b.runtimeData.pop("symbol") + let parameters = b.randomParameters() + b.setParameterTypesForNextSubroutine(parameters.parameterTypes) + b.emit( + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), + withInputs: [symbol]) + }, + GeneratorStub( + "DisposableClassInstanceComputedMethodEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]), + provides: [.classDefinition] + ) { b in + b.maybeReturnRandomJsVariable(0.9) + b.emit(EndClassComputedMethod()) + }, + GeneratorStub( + "DisposableClassDefinitionEndGenerator", + inContext: .single(.classDefinition) + ) { b in + b.emit(EndClassDefinition()) + let cls = b.runtimeData.pop("class") + let disposableVariable = b.construct( + cls, withArgs: b.randomArguments(forCalling: cls)) + genDisposableVariable(b, disposableVariable) + }, + ] +} + // // Code generators. // @@ -98,6 +168,23 @@ public let CodeGenerators: [CodeGenerator] = [ b.loadString(b.randomString()) }, + 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"; + let selectLhs = inputString + let selectRhs = b.randomVariable(ofType: .string)! + let cond = b.randomJsVariable() + let select = b.ternary(cond, selectLhs, selectRhs) + let other = b.randomVariable(ofType: .string)! + if Bool.random() { + b.binary(select, other, with: .Add) + } else { + b.binary(other, select, with: .Add) + } + }, + CodeGenerator("BooleanGenerator", produces: [.boolean]) { b in // It's probably not too useful to generate multiple boolean values here. b.loadBool(Bool.random()) @@ -135,6 +222,49 @@ public let CodeGenerators: [CodeGenerator] = [ b.createFloatArray(with: values) }, + CodeGenerator("HoleyArrayGenerator", inputs: .one, produces: [.jsArray]) { b, _ in + let undefined = b.loadUndefined() + // Hide 'undefined' so it is for sure inlined, allowing the lifter to produce holes [,,]. + // NOTE: undefineds are lifted to holes + b.hide(undefined) + + var size = Int.random(in: 1...7) + var elements = [Variable]() + + // Randomly select the type of elements to surround the holes with. + let getElementOptions: [() -> Variable] = [ + // Holey Smi (in most cases) + { b.randomVariable(ofType: .integer) ?? b.loadInt(b.randomInt()) }, + // Holey Double + { b.randomVariable(ofType: .float) ?? b.loadFloat(b.randomFloat()) }, + // Holey Elements + { b.randomJsVariable() }, + ] + let getElement = getElementOptions.randomElement()! + + let guaranteeHole = Int.random(in: 0..= 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) }, @@ -556,8 +793,7 @@ public let CodeGenerators: [CodeGenerator] = [ b.currentObjectLiteral.copyProperties(from: object) }, - CodeGenerator("ObjectLiteralPrototypeGenerator", inContext: .single(.objectLiteral)) - { b in + CodeGenerator("ObjectLiteralPrototypeGenerator", inContext: .single(.objectLiteral)) { b in // There should only be one __proto__ field in an object literal. guard !b.currentObjectLiteral.hasPrototype else { return } @@ -573,18 +809,26 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method] ) { b in // Try to find a method that hasn't already been added to this literal. - let methodName = b.generateString(b.randomCustomMethodName, + let methodName = b.generateString( + 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", inContext: .single([.javascript, .subroutine, .method])) { b in + GeneratorStub( + "ObjectLiteralMethodEndGenerator", + inContext: .single([.javascript, .subroutine, .method]) + ) { b in b.emit(EndObjectLiteralMethod()) }, ]), @@ -598,25 +842,17 @@ 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 parameters = b.randomParameters() + let methodName = b.randomJsVariable( + notIn: b.currentObjectLiteral.computedMethods) + 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", @@ -625,7 +861,6 @@ public let CodeGenerators: [CodeGenerator] = [ ) { b, inp in b.doReturn(inp) b.emit(EndObjectLiteralComputedMethod()) - }, ]), @@ -638,10 +873,10 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method] ) { b in // Try to find a property that hasn't already been added and for which a getter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentObjectLiteral.properties + b.currentObjectLiteral.getters) b.emit(BeginObjectLiteralGetter(propertyName: propertyName)) - }, GeneratorStub( "ObjectLiteralGetterEndGenerator", @@ -662,7 +897,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method] ) { b in // Try to find a property that hasn't already been added and for which a setter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentObjectLiteral.properties + b.currentObjectLiteral.setters) b.emit(BeginObjectLiteralSetter(propertyName: propertyName)) }, @@ -674,6 +910,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", [ @@ -689,17 +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 - let this = args[0] + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: args.last!) + } + + 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()` @@ -724,18 +1008,17 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), - CodeGenerator("ClassInstancePropertyGenerator", inContext: .single(.classDefinition)) - { b in + CodeGenerator("ClassInstancePropertyGenerator", inContext: .single(.classDefinition)) { b in // Try to find a property that hasn't already been added to this literal. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties) var value: Variable? = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addInstanceProperty(propertyName, value: value) }, - CodeGenerator("ClassInstanceElementGenerator", inContext: .single(.classDefinition)) - { b in + CodeGenerator("ClassInstanceElementGenerator", inContext: .single(.classDefinition)) { b in // Select an element that hasn't already been added to this literal. var index = b.randomIndex() while b.currentClassDefinition.instanceElements.contains(index) { @@ -751,15 +1034,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) @@ -774,22 +1050,28 @@ 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. - let methodName = b.generateString(b.randomCustomMethodName, + let methodName = b.generateString( + 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( - BeginClassInstanceMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: false), + withInputs: defaultValues) }, GeneratorStub( "ClassInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) }, ]), @@ -802,28 +1084,25 @@ 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 parameters = b.randomParameters() + let methodName = b.randomJsVariable( + notIn: b.currentClassDefinition.instanceComputedMethods) + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceComputedMethod( - parameters: parameters.parameters), - withInputs: [methodName]) + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), + withInputs: [methodName] + defaultValues) }, GeneratorStub( "ClassInstanceComputedMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -836,16 +1115,18 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a property that hasn't already been added and for which a getter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties - + b.currentClassDefinition.instanceGetters) - b.emit(BeginClassInstanceGetter(propertyName: propertyName)) + + b.currentClassDefinition.instanceGetters) + b.emit(BeginClassGetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( - "ClassInstanceGetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) + "ClassInstanceGetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.doReturn(b.randomJsVariable()) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassGetter()) }, ]), @@ -858,16 +1139,17 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a property that hasn't already been added and for which a setter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties - + b.currentClassDefinition.instanceSetters) - b.emit(BeginClassInstanceSetter(propertyName: propertyName)) + + b.currentClassDefinition.instanceSetters) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( "ClassInstanceSetterEndGenerator", inContext: .single([.javascript, .method, .subroutine, .classMethod]) ) { b in - b.emit(EndClassInstanceSetter()) + b.emit(EndClassSetter()) }, ]), @@ -875,7 +1157,8 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("ClassStaticPropertyGenerator", inContext: .single(.classDefinition)) { b in // Try to find a property that hasn't already been added to this literal. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties) var value: Variable? = probability(0.5) ? b.randomJsVariable() : nil @@ -899,18 +1182,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) @@ -943,15 +1216,21 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .method, .subroutine, .classMethod] ) { b in // Try to find a method that hasn't already been added to this class. - let methodName = b.generateString(b.randomCustomMethodName, + 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( - BeginClassStaticMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: true), + withInputs: defaultValues) }, GeneratorStub( @@ -959,7 +1238,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .classMethod, .subroutine, .method]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) }, ]), @@ -972,20 +1251,14 @@ 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( - BeginClassStaticComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: true), withInputs: [methodName]) }, GeneratorStub( @@ -993,7 +1266,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -1006,17 +1279,18 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a property that hasn't already been added and for which a getter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties - + b.currentClassDefinition.staticGetters) - b.emit(BeginClassStaticGetter(propertyName: propertyName)) + + b.currentClassDefinition.staticGetters) + 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()) }, ]), @@ -1029,16 +1303,66 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a property that hasn't already been added and for which a setter has not yet been installed. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties - + b.currentClassDefinition.staticSetters) - b.emit(BeginClassStaticSetter(propertyName: propertyName)) + + b.currentClassDefinition.staticSetters) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: true)) }, GeneratorStub( "ClassStaticSetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.emit(EndClassStaticSetter()) + b.emit(EndClassSetter()) + }, + ]), + + 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()) }, ]), @@ -1046,7 +1370,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassPrivateInstancePropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a private field that hasn't already been added to this literal. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.privateFields) var value = probability(0.5) ? b.randomJsVariable() : nil @@ -1062,21 +1387,23 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.classDefinition), provides: [.javascript, .subroutine, .method, .classMethod] ) { b in - // Try to find a private field that hasn't already been added to this class. - let methodName = b.generateString(b.randomCustomMethodName, + // Try to find a private method that hasn't already been added to this class. + let methodName = b.generateString( + b.randomCustomPrivateMethodName, 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()) }, ]), @@ -1084,7 +1411,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassPrivateStaticPropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a private field that hasn't already been added to this literal. - let propertyName = b.generateString(b.randomCustomPropertyName, + let propertyName = b.generateString( + b.randomCustomPropertyName, notIn: b.currentClassDefinition.privateFields) var value = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addPrivateStaticProperty( @@ -1099,21 +1427,23 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.classDefinition), provides: [.javascript, .subroutine, .method, .classMethod] ) { b in - // Try to find a private field that hasn't already been added to this class. - let methodName = b.generateString(b.randomCustomMethodName, + // Try to find a private method that hasn't already been added to this class. + let methodName = b.generateString( + b.randomCustomPrivateMethodName, 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()) }, ]), @@ -1192,45 +1522,71 @@ 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", [ - GeneratorStub("PlainFunctionBeginGenerator", provides: [.javascript, .subroutine]) { b in - let randomParameters = b.randomParameters() - b.setParameterTypesForNextSubroutine( - randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) - }, - GeneratorStub("PlainFunctionEndGenerator", inContext: .single([.javascript, .subroutine])) { b in - b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable - b.emit(EndPlainFunction()) - let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) - b.callFunction(f, withArgs: arguments, guard: !matches) - }, - ]), - - CodeGenerator("StrictModeFunctionGenerator", [ - GeneratorStub("StrictModeFunctionBeginGenerator", provides: [.subroutine, .javascript]) { 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() - b.setParameterTypesForNextSubroutine( - randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) - b.directive("use strict") - }, - GeneratorStub("StrictModeFunctionEndGenerator", inContext: .single([.javascript, .subroutine])) { b in - b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable - b.emit(EndPlainFunction()) - let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) - b.callFunction(f, withArgs: arguments, guard: !matches) - }, - ]), + CodeGenerator( + "PlainFunctionGenerator", + [ + GeneratorStub("PlainFunctionBeginGenerator", provides: [.javascript, .subroutine]) { + b in + 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), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } + b.runtimeData.push("plainFunction", instr.output) + }, + GeneratorStub( + "PlainFunctionEndGenerator", inContext: .single([.javascript, .subroutine]) + ) { b in + b.doReturn(b.randomJsVariable()) + b.emit(EndPlainFunction()) + let f = b.runtimeData.pop("plainFunction") + let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) + b.callFunction(f, withArgs: arguments, guard: !matches) + }, + ]), + + CodeGenerator( + "StrictModeFunctionGenerator", + [ + GeneratorStub("StrictModeFunctionBeginGenerator", provides: [.subroutine, .javascript]) + { 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, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) + b.setParameterTypesForNextSubroutine( + randomParameters.parameterTypes) + let instr = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } + b.runtimeData.push("strictFunction", instr.output) + b.directive("use strict") + }, + GeneratorStub( + "StrictModeFunctionEndGenerator", inContext: .single([.javascript, .subroutine]) + ) { b in + b.doReturn(b.randomJsVariable()) + b.emit(EndPlainFunction()) + let f = b.runtimeData.pop("strictFunction") + let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) + b.callFunction(f, withArgs: arguments, guard: !matches) + }, + ]), CodeGenerator( "ArrowFunctionGenerator", @@ -1239,11 +1595,18 @@ 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) - b.emit( - BeginArrowFunction(parameters: randomParameters.parameters)) + let instr = b.emit( + BeginArrowFunction(parameters: randomParameters.parameters), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } }, GeneratorStub( "ArrowFunctionEndGenerator", @@ -1254,48 +1617,80 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), - CodeGenerator("GeneratorFunctionGenerator", [ - GeneratorStub("GeneratorFunctionBeginGenerator", provides: [.generatorFunction, .subroutine, .javascript]) { b in - let randomParameters = b.randomParameters() - b.setParameterTypesForNextSubroutine( - randomParameters.parameterTypes) - b.emit( - BeginGeneratorFunction(parameters: randomParameters.parameters, functionName: nil)) - }, - GeneratorStub("GeneratorFunctionEndGenerator", inContext: .single([.generatorFunction, .subroutine, .javascript])) { b in - if probability(0.5) { - b.yield(b.randomJsVariable()) - } else { - let randomVariables = b.randomJsVariables( - n: Int.random(in: 1...5)) - let array = b.createArray(with: randomVariables) - b.yieldEach(array) - } - b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable - b.emit(EndGeneratorFunction()) - let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) - b.callFunction(f, withArgs: arguments, guard: !matches) - }, - ]), + CodeGenerator( + "GeneratorFunctionGenerator", + [ + GeneratorStub( + "GeneratorFunctionBeginGenerator", + provides: [.generatorFunction, .subroutine, .javascript] + ) { b in + 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), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } + b.runtimeData.push("generatorFunction", instr.output) + }, + GeneratorStub( + "GeneratorFunctionEndGenerator", + inContext: .single([.generatorFunction, .subroutine, .javascript]) + ) { b in + if probability(0.5) { + b.yield(b.randomJsVariable()) + } else { + let randomVariables = b.randomJsVariables( + n: Int.random(in: 1...5)) + let array = b.createArray(with: randomVariables) + b.yieldEach(array) + } + b.doReturn(b.randomJsVariable()) + b.emit(EndGeneratorFunction()) + let f = b.runtimeData.pop("generatorFunction") + let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) + b.callFunction(f, withArgs: arguments, guard: !matches) + }, + ]), - CodeGenerator("AsyncFunctionGenerator", [ - GeneratorStub("AsyncFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction]) { b in - let randomParameters = b.randomParameters() - b.setParameterTypesForNextSubroutine( - randomParameters.parameterTypes) - b.emit( - BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)) - }, - GeneratorStub("AsyncFunctionEndGenerator", inContext: .single([.javascript, .subroutine, .asyncFunction])) { b in - b.await(b.randomJsVariable()) - b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable - b.emit(EndAsyncFunction()) - let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) - b.callFunction(f, withArgs: arguments, guard: !matches) - }, - ]), + CodeGenerator( + "AsyncFunctionGenerator", + [ + GeneratorStub( + "AsyncFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction] + ) { b in + 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), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } + b.runtimeData.push("asyncFunction", instr.output) + }, + GeneratorStub( + "AsyncFunctionEndGenerator", + inContext: .single([.javascript, .subroutine, .asyncFunction]) + ) { b in + b.await(b.randomJsVariable()) + b.doReturn(b.randomJsVariable()) + b.emit(EndAsyncFunction()) + let f = b.runtimeData.pop("asyncFunction") + let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) + b.callFunction(f, withArgs: arguments, guard: !matches) + }, + ]), CodeGenerator( "AsyncArrowFunctionGenerator", @@ -1304,12 +1699,18 @@ 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) - b.emit( + 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!) + } }, GeneratorStub( "AsyncArrowFunctionAwaitGenerator", @@ -1330,32 +1731,48 @@ public let CodeGenerators: [CodeGenerator] = [ // This should likely be a Generator. // Cannot mark this as producing, as that would turn this into a value generator, but we call into .build. - CodeGenerator("AsyncGeneratorFunctionGenerator", [ - GeneratorStub("AsyncGeneratorFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction, .generatorFunction]) { b in - let randomParameters = b.randomParameters() - b.setParameterTypesForNextSubroutine( - randomParameters.parameterTypes) - b.emit( - BeginAsyncGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) - }, - GeneratorStub("AsyncGeneratorFunctionEndGenerator", inContext: .single([.javascript, .subroutine, .generatorFunction, .asyncFunction])) { b in - b.await(b.randomJsVariable()) - if probability(0.5) { - b.yield(b.randomJsVariable()) - } else { - let randomVariables = b.randomJsVariables( - n: Int.random(in: 1...5)) - let array = b.createArray(with: randomVariables) - b.yieldEach(array) - } - b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable - b.emit(EndAsyncGeneratorFunction()) - let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) - b.callFunction(f, withArgs: arguments, guard: !matches) - }, - ]), + CodeGenerator( + "AsyncGeneratorFunctionGenerator", + [ + GeneratorStub( + "AsyncGeneratorFunctionBeginGenerator", + provides: [.javascript, .subroutine, .asyncFunction, .generatorFunction] + ) { b in + 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), + withInputs: defaultValues) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } + b.runtimeData.push("asyncGeneratorFunction", instr.output) + }, + GeneratorStub( + "AsyncGeneratorFunctionEndGenerator", + inContext: .single([.javascript, .subroutine, .generatorFunction, .asyncFunction]) + ) { b in + b.await(b.randomJsVariable()) + if probability(0.5) { + b.yield(b.randomJsVariable()) + } else { + let randomVariables = b.randomJsVariables( + n: Int.random(in: 1...5)) + let array = b.createArray(with: randomVariables) + b.yieldEach(array) + } + b.doReturn(b.randomJsVariable()) + b.emit(EndAsyncGeneratorFunction()) + let f = b.runtimeData.pop("asyncGeneratorFunction") + let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) + b.callFunction(f, withArgs: arguments, guard: !matches) + }, + ]), CodeGenerator("PropertyRetrievalGenerator", inputs: .preferred(.object())) { b, obj in @@ -1374,13 +1791,13 @@ public let CodeGenerators: [CodeGenerator] = [ // console.log(y() === x); // false CodeGenerator("MethodAsPropertyRetrievalGenerator", inputs: .preferred(.object())) { b, obj in let type = b.type(of: obj) - let propertyName = type.randomMethod() ?? type.randomProperty() ?? b.randomCustomPropertyName() + let propertyName = + type.randomMethod() ?? type.randomProperty() ?? b.randomCustomPropertyName() let needGuard = b.type(of: obj).MayBe(.nullish) b.getProperty(propertyName, of: obj, guard: needGuard) }, - CodeGenerator("PropertyAssignmentGenerator", inputs: .preferred(.object())) - { b, obj in + CodeGenerator("PropertyAssignmentGenerator", inputs: .preferred(.object())) { b, obj in let propertyName: String // Either change an existing property or define a new one if probability(0.5) { @@ -1616,6 +2033,40 @@ 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.. GeneratorStub { - for generator in self { - if generator.name == name { - return generator - } + CodeGenerator( + "ResizableBufferResizeGenerator", + inContext: .single(.javascript), + inputs: .required(.jsArrayBuffer) + ) { b, buffer in + let numPages = Int64.random(in: 0...256) + let newSize: Variable + // WebAssembly memories cannot shrink, and must be a multiple of the page size. + if probability(0.5) { + newSize = b.loadInt(numPages * Int64(WasmConstants.specWasmMemPageSize)) + } else { + newSize = b.loadInt(Int64.random(in: 0...0x1000000)) } - fatalError("Unknown code generator \(name)") - } -} + b.callMethod("resize", on: buffer, withArgs: [newSize], guard: true) + }, + + CodeGenerator( + "GrowableSharedBufferGrowGenerator", + inContext: .single(.javascript), + inputs: .required(.jsSharedArrayBuffer) + ) { b, buffer in + let currentByteLength = b.getProperty("byteLength", of: buffer) + let numPages = Int64.random(in: 0...16) + // WebAssembly memories must be a multiple of the page size. + let delta: Variable + if probability(0.5) { + delta = b.loadInt(numPages * Int64(WasmConstants.specWasmMemPageSize)) + } else { + delta = b.loadInt(Int64.random(in: 0...0x100000)) + } + 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/CodeGen/ProgramTemplate.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplate.swift index 17a06a60a..c23adae55 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplate.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplate.swift @@ -13,9 +13,9 @@ // limitations under the License. public class ProgramTemplate: Contributor { - private let f: (ProgramBuilder) -> () + 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/ProgramTemplateWeights.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift index c57cf76b4..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, @@ -27,4 +28,6 @@ public let programTemplateWeights = [ "JITTrickyFunction": 2, "JSONFuzzer": 1, "WasmReturnCalls": 2, + "WasmResizableMemory": 2*6, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. + "WasmMemoryBufferReattachment": 2*6, ] diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 126519941..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) }, @@ -146,34 +153,41 @@ public let ProgramTemplates = [ // A few tags (wasm exception kinds) to be used later on. let wasmTags = (0...Int.random(in: 0..<5)).map { _ in - b.createWasmTag(parameterTypes: b.randomTagParameters()) + b.createWasmTag(parameterTypes: b.randomTagParametersJs()) } let tags = [b.createWasmJSTag()] + wasmTags 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) } b.build(n: 10) - function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef)!) + function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef())!) return [] } } @@ -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) + + let isMem64 = b.type(of: mem).wasmMemoryType!.isMemory64 + let pagesToGrow = isMem64 ? f.extendi32Toi64(args[0], isSigned: false) : args[0] + let oldSize = f.wasmMemoryGrow(memory: mem, growByPages: pagesToGrow) + + return [isMem64 ? f.wrapi64Toi32(oldSize) : oldSize] + } + } + let exports = module.loadExports() + let memory = b.getProperty("wm0", of: exports) + let wasmGrow = b.getProperty("w0", of: exports) + + // 2. JS Loop + b.buildRepeatLoop(n: 20) { _ in + + // 3. Swift Loop: Unroll a long sequence of mixed operations + let steps = Int.random(in: 2...3) + for _ in 0.. Resizable) + if probability(0.5) { + b.callMethod("toResizableBuffer", on: memory) + } else { + b.callMethod("toFixedLengthBuffer", on: memory) + } + + b.build(n: 3) + + // 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 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]) + } + }) + } + b.build(n: 15) + } + }, ] diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index f63a168e5..e0676a9fc 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( @@ -52,7 +53,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ if probability(0.5) { b.createWasmJSTag() } else { - b.createWasmTag(parameterTypes: b.randomTagParameters()) + b.createWasmTag(parameterTypes: b.randomTagParametersJs()) } }, // @@ -77,105 +78,89 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ]), - CodeGenerator("WasmTypeGroupGenerator", [ - GeneratorStub( - "WasmTypeGroupBeginGenerator", - provides: [.wasmTypeGroup] - ) { b in - b.emit(WasmBeginTypeGroup()) - }, - GeneratorStub( - "WasmTypeGroupEndGenerator", - inContext: .single(.wasmTypeGroup) - ) { b in - // Collect all types that are visible and expose them. - let types = b.scopes.top.filter { - let t = b.type(of: $0) - return t.Is(.wasmTypeDef()) - && t.wasmTypeDefinition?.description != .selfReference - } - b.emit( - WasmEndTypeGroup(typesCount: types.count), withInputs: types - ) - }, - ]), - - // TODO: refine this `produces` annotation? CodeGenerator( - "WasmArrayTypeGenerator", - inContext: .single(.wasmTypeGroup), - produces: [.wasmTypeDef()] - ) { b in - let mutability = probability(0.75) - if let elementType = b.randomVariable(ofType: .wasmTypeDef()), - probability(0.25) - { - // Excluding non-nullable references from referring to a self-reference ensures we do not end up with cycles of non-nullable references. - let nullability = - b.type(of: elementType).wasmTypeDefinition!.description - == .selfReference || probability(0.5) - b.wasmDefineArrayType( - elementType: .wasmRef(.Index(), nullability: nullability), - mutability: mutability, indexType: elementType) - } else { - b.wasmDefineArrayType( - elementType: chooseUniform(from: [ - .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, - ]), mutability: mutability) - } - }, + "WasmTypeGroupGenerator", + [ + GeneratorStub( + "WasmTypeGroupBeginGenerator", + provides: [.wasmTypeGroup] + ) { b in + b.emit(WasmBeginTypeGroup()) + }, + GeneratorStub( + "WasmTypeGroupEndGenerator", + inContext: .single(.wasmTypeGroup) + ) { b in + b.wasmEndTypeGroup() + }, + ]), - CodeGenerator("WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), produces: [.wasmTypeDef()]) { b in - var indexTypes: [Variable] = [] - let fields = (0.. 0 + else { fatalError("The type \(abstractType) doesn't belong in any hierarchy") } + + let chosenType = chooseUniform(from: sameHierarchy) + function.wasmRefTest( + ref, + refType: .wasmRef( + .Abstract(HeapTypeInfo(chosenType, shared: false)), nullability: Bool.random()) + ) + }, + + CodeGenerator( + "WasmRefCastGenerator", inContext: .single(.wasmFunction), + inputs: .requiredComplex(.init(.wasmTypeDef())), + produces: [.wasmGenericRef] + ) { b, typeDef in + guard + let abstractType = + b.type(of: typeDef).wasmTypeDefinition?.description?.abstractHeapSupertype?.heapType + as? WasmAbstractHeapType + else { fatalError("Invalid type description for \(b.type(of: typeDef))") } + let function = b.currentWasmModule.currentWasmFunction + let variable = + switch abstractType { + case .WasmFunc, .WasmNoFunc: + function.findOrGenerateWasmVar(ofType: .wasmFuncRef()) + case .WasmArray, .WasmStruct: + function.findOrGenerateWasmVar(ofType: .wasmAnyRef()) + default: + fatalError("The type \(abstractType) shouldn't have a definition") + } + let refType = ILType.wasmRef(.Index(), nullability: Bool.random()) + function.wasmRefCast(variable, refType: refType, typeDef: typeDef) + }, + + CodeGenerator( + "WasmRefCastAbstractGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmGenericRef), + produces: [.wasmGenericRef] + ) { b, ref in + let function = b.currentWasmModule.currentWasmFunction + let heapType = + switch b.type(of: ref).wasmReferenceType!.kind { + case .Abstract(let heapTypeInfo): + heapTypeInfo.heapType + case .Index(let desc): + desc.get()!.abstractHeapSupertype!.heapType + } + let incompatible: [WasmAbstractHeapType] = [.WasmStruct, .WasmArray, .WasmI31] + let chosenType = chooseUniform( + from: WasmAbstractHeapType.allCases.filter { + $0 != heapType && $0.inSameHierarchy(heapType) + && ( // 90% of the time it won't contain two incompatible types + probability(0.1) + || !(incompatible.contains($0) && incompatible.contains(heapType))) + } + ) + // TODO(pawkra): add shared variant. + let newType = ILType.wasmRef( + .Abstract(HeapTypeInfo(chosenType, shared: false)), nullability: Bool.random()) + function.wasmRefCast(ref, refType: newType) + }, + // Primitive Value Generators CodeGenerator( @@ -420,7 +561,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ ? WasmConstants.specMaxWasmMem64Pages : WasmConstants.specMaxWasmMem32Pages)) } - module.addMemory(minPages: minPages, maxPages: maxPages, isShared: isShared, isMemory64: isMemory64) + module.addMemory( + minPages: minPages, maxPages: maxPages, isShared: isShared, isMemory64: isMemory64) }, CodeGenerator("WasmDefineDataSegmentGenerator", inContext: .single(.wasm)) { b in @@ -469,29 +611,43 @@ public let WasmCodeGenerators: [CodeGenerator] = [ } }, - CodeGenerator("WasmAtomicLoadGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in + CodeGenerator( + "WasmAtomicLoadGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in let function = b.currentWasmModule.currentWasmFunction let loadType = chooseUniform(from: WasmAtomicLoadType.allCases) let alignment = loadType.naturalAlignment() - let (address, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: memory, alignment: alignment) + let (address, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: memory, alignment: alignment) - function.wasmAtomicLoad(memory: memory, address: address, loadType: loadType, offset: staticOffset) + function.wasmAtomicLoad( + memory: memory, address: address, loadType: loadType, offset: staticOffset) }, - CodeGenerator("WasmAtomicStoreGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in + CodeGenerator( + "WasmAtomicStoreGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in let function = b.currentWasmModule.currentWasmFunction let storeType = chooseUniform(from: WasmAtomicStoreType.allCases) let alignment = storeType.naturalAlignment() guard let value = b.randomVariable(ofType: storeType.numberType()) else { return } - let (address, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: memory, alignment: alignment) + let (address, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: memory, alignment: alignment) - function.wasmAtomicStore(memory: memory, address: address, value: value, storeType: storeType, offset: staticOffset) + function.wasmAtomicStore( + memory: memory, address: address, value: value, storeType: storeType, + offset: staticOffset) }, - CodeGenerator("WasmAtomicRMWGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in + CodeGenerator( + "WasmAtomicRMWGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in let function = b.currentWasmModule.currentWasmFunction let op = chooseUniform(from: WasmAtomicRMWType.allCases) let valueType = op.type() @@ -499,12 +655,16 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let rhs = function.findOrGenerateWasmVar(ofType: valueType) - let (lhs, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: memory, alignment: alignment) + let (lhs, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: memory, alignment: alignment) function.wasmAtomicRMW(memory: memory, lhs: lhs, rhs: rhs, op: op, offset: staticOffset) }, - CodeGenerator("WasmAtomicCmpxchgGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in + CodeGenerator( + "WasmAtomicCmpxchgGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in let function = b.currentWasmModule.currentWasmFunction let op = chooseUniform(from: WasmAtomicCmpxchgType.allCases) let valueType = op.type() @@ -513,9 +673,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let expected = function.findOrGenerateWasmVar(ofType: valueType) let replacement = function.findOrGenerateWasmVar(ofType: valueType) - let (address, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: memory, alignment: alignment) + let (address, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: memory, alignment: alignment) - function.wasmAtomicCmpxchg(memory: memory, address: address, expected: expected, replacement: replacement, op: op, offset: staticOffset) + function.wasmAtomicCmpxchg( + memory: memory, address: address, expected: expected, replacement: replacement, op: op, + offset: staticOffset) }, // We don't specify what type this produces as it could be a .wasmi64 or a .wasmi32, depending on the WasmMemory object. @@ -539,16 +702,19 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmMemoryGrow(memory: memory, growByPages: growBy) }, - CodeGenerator("WasmMemoryCopyGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, srcMemory in + CodeGenerator( + "WasmMemoryCopyGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, srcMemory in let function = b.currentWasmModule.currentWasmFunction let srcMemoryTypeInfo = b.type(of: srcMemory).wasmMemoryType! - let dstMemory = b.findVariable {v in - let type = b.type(of: v) - return type.Is(.object(ofGroup: "WasmMemory")) - && type.wasmMemoryType!.isMemory64 == srcMemoryTypeInfo.isMemory64 + let dstMemory = b.findVariable { v in + let type = b.type(of: v) + return type.Is(.object(ofGroup: "WasmMemory")) + && type.wasmMemoryType!.isMemory64 == srcMemoryTypeInfo.isMemory64 }! let dstMemoryTypeInfo = b.type(of: srcMemory).wasmMemoryType! - let memArg = {v in function.memoryArgument(v, dstMemoryTypeInfo)} + let memArg = { v in function.memoryArgument(v, dstMemoryTypeInfo) } let srcMemSize = srcMemoryTypeInfo.limits.min * WasmConstants.specWasmMemPageSize let dstMemSize = dstMemoryTypeInfo.limits.min * WasmConstants.specWasmMemPageSize @@ -557,15 +723,21 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let dstOffsetValue = b.randomNonNegativeIndex(upTo: Int64(dstMemSize)) let dstOffset = memArg(dstOffsetValue) - let maxCopySize = min(Int64(srcMemSize) - srcOffsetValue, Int64(dstMemSize) - dstOffsetValue) - let copySizeValue = b.randomSize(upTo:maxCopySize) + let maxCopySize = min( + Int64(srcMemSize) - srcOffsetValue, Int64(dstMemSize) - dstOffsetValue) + let copySizeValue = b.randomSize(upTo: maxCopySize) let copySize = memArg(copySizeValue) - function.wasmMemoryCopy(dstMemory: dstMemory, srcMemory: srcMemory, dstOffset: dstOffset, srcOffset: srcOffset, size: copySize) + function.wasmMemoryCopy( + dstMemory: dstMemory, srcMemory: srcMemory, dstOffset: dstOffset, srcOffset: srcOffset, + size: copySize) }, - CodeGenerator("WasmMemoryFillGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in - if (b.hasZeroPages(memory: memory)) { return } + CodeGenerator( + "WasmMemoryFillGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in + if b.hasZeroPages(memory: memory) { return } let function = b.currentWasmModule.currentWasmFunction let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -574,13 +746,22 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let offsetValue = b.randomNonNegativeIndex(upTo: memSize) let offset = function.memoryArgument(offsetValue, memoryTypeInfo) let byteToSet = function.consti32(Int32.random(in: 0...255)) - let nrOfBytesToUpdate = function.memoryArgument(Int64.random(in: 0...(memSize - offsetValue)) + 1, memoryTypeInfo) + let nrOfBytesToUpdate = function.memoryArgument( + Int64.random(in: 0...(memSize - offsetValue)) + 1, memoryTypeInfo) - function.wasmMemoryFill(memory: memory, offset: offset, byteToSet: byteToSet, nrOfBytesToUpdate: nrOfBytesToUpdate) + function.wasmMemoryFill( + memory: memory, offset: offset, byteToSet: byteToSet, + nrOfBytesToUpdate: nrOfBytesToUpdate) }, - CodeGenerator("WasmMemoryInitGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmMemory"), .wasmDataSegment())) { b, memory, dataSegment in - if (b.hasZeroPages(memory: memory) || b.type(of: dataSegment).wasmDataSegmentType!.isDropped) { return } + CodeGenerator( + "WasmMemoryInitGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmMemory"), .wasmDataSegment()) + ) { b, memory, dataSegment in + if b.hasZeroPages(memory: memory) || b.type(of: dataSegment).wasmDataSegmentType!.isDropped + { + return + } let function = b.currentWasmModule.currentWasmFunction @@ -590,16 +771,24 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let memoryOffset = function.memoryArgument(memoryOffsetValue, memoryTypeInfo) let dataSegmentTypeInfo = b.type(of: dataSegment).wasmDataSegmentType! - let dataSegmentOffsetValue = b.randomNonNegativeIndex(upTo: Int64(dataSegmentTypeInfo.segmentLength)) + let dataSegmentOffsetValue = b.randomNonNegativeIndex( + upTo: Int64(dataSegmentTypeInfo.segmentLength)) let dataSegmentOffset = function.consti32(Int32(dataSegmentOffsetValue)) - let maxNrOfBytesToUpdate = min(memSize - memoryOffsetValue, Int64(dataSegmentTypeInfo.segmentLength) - dataSegmentOffsetValue) + let maxNrOfBytesToUpdate = min( + memSize - memoryOffsetValue, + Int64(dataSegmentTypeInfo.segmentLength) - dataSegmentOffsetValue) let nrOfBytesToUpdate = function.consti32(Int32(b.randomSize(upTo: maxNrOfBytesToUpdate))) - function.wasmMemoryInit(dataSegment: dataSegment, memory: memory, memoryOffset: memoryOffset, dataSegmentOffset: dataSegmentOffset, nrOfBytesToUpdate: nrOfBytesToUpdate) + function.wasmMemoryInit( + dataSegment: dataSegment, memory: memory, memoryOffset: memoryOffset, + dataSegmentOffset: dataSegmentOffset, nrOfBytesToUpdate: nrOfBytesToUpdate) }, - CodeGenerator("WasmDropDataSegmentGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmDataSegment())) { b, dataSegment in + CodeGenerator( + "WasmDropDataSegmentGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmDataSegment()) + ) { b, dataSegment in b.currentWasmFunction.wasmDropDataSegment(dataSegment: dataSegment) }, @@ -623,7 +812,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(manoskouk): Generalize these. let minSize = 10 let maxSize: Int? = nil - let elementType = ILType.wasmFuncRef + let elementType = ILType.wasmFuncRef() let definedEntryIndices: [Int] var definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [] @@ -636,7 +825,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // Currently, only generate entries for funcref tables. // TODO(manoskouk): Generalize this. - if elementType == .wasmFuncRef { + if elementType == .wasmFuncRef() { if b.randomVariable(ofType: expectedEntryType) != nil { // There is at least one function in scope. Add some initial entries to the table. // TODO(manoskouk): Generalize this. @@ -665,28 +854,43 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, CodeGenerator("WasmDefineElementSegmentGenerator", inContext: .single(.wasm)) { b in - let expectedEntryType = b.currentWasmModule.getEntryTypeForTable(elementType: ILType.wasmFuncRef) + let expectedEntryType = b.currentWasmModule.getEntryTypeForTable( + elementType: .wasmFuncRef()) if b.randomVariable(ofType: expectedEntryType) == nil { return } - var elements: [Variable] = (0...Int.random(in: 0...8)).map {_ in b.randomVariable(ofType: expectedEntryType)!} + var elements: [Variable] = (0...Int.random(in: 0...8)).map { _ in + b.randomVariable(ofType: expectedEntryType)! + } b.currentWasmModule.addElementSegment(elements: elements) }, - CodeGenerator("WasmDropElementSegmentGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmElementSegment())) { b, elementSegment in + CodeGenerator( + "WasmDropElementSegmentGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmElementSegment()) + ) { b, elementSegment in b.currentWasmFunction.wasmDropElementSegment(elementSegment: elementSegment) }, - CodeGenerator("WasmTableSizeGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmTable"))) { b, table in + CodeGenerator( + "WasmTableSizeGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmTable")) + ) { b, table in let function = b.currentWasmModule.currentWasmFunction function.wasmTableSize(table: table) }, - CodeGenerator("WasmTableGrowGenerator", inContext: .single(.wasmFunction), inputs: .required(.object(ofGroup: "WasmTable"))) { b, table in + CodeGenerator( + "WasmTableGrowGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmTable")) + ) { b, table in let function = b.currentWasmModule.currentWasmFunction let tableType = b.type(of: table).wasmTableType! - let delta = tableType.isTable64 ? function.consti64(Int64.random(in: 0...10)) : function.consti32(Int32.random(in: 0...10)) + let delta = + tableType.isTable64 + ? function.consti64(Int64.random(in: 0...10)) + : function.consti32(Int32.random(in: 0...10)) let initialValue = function.findOrGenerateWasmVar(ofType: tableType.elementType) function.wasmTableGrow(table: table, with: initialValue, by: delta) }, @@ -696,7 +900,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inputs: .required(.object(ofGroup: "WasmTable")) ) { b, table in let tableType = b.type(of: table).wasmTableType! - if !tableType.elementType.Is(.wasmFuncRef) { return } + if !tableType.elementType.Is(.wasmFuncRef()) { return } guard let indexedSignature = tableType.knownEntries.randomElement() else { return } @@ -756,7 +960,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ ) { b, table in let function = b.currentWasmModule.currentWasmFunction let tableType = b.type(of: table).wasmTableType! - if !tableType.elementType.Is(.wasmFuncRef) { return } + if !tableType.elementType.Is(.wasmFuncRef()) { return } guard let indexedSignature = (tableType.knownEntries.filter { @@ -1174,8 +1378,15 @@ 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", @@ -1183,14 +1394,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) }, ]), @@ -1238,13 +1446,16 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inContext: .single(.wasmFunction), provides: [.wasmFunction] ) { b in - b.emit(WasmBeginBlock(with: [] => [])) + let signature = b.wasmDefineAdHocSignatureType(signature: [] => []) + b.runtimeData.push("blockSignature", signature) + b.emit(WasmBeginBlock(parameterCount: 0), withInputs: [signature]) }, GeneratorStub( "WasmEndBlockGenerator", inContext: .single(.wasmFunction) ) { b in - b.emit(WasmEndBlock(outputTypes: [])) + b.emit( + WasmEndBlock(outputCount: 0), withInputs: [b.runtimeData.pop("blockSignature")]) }, ]), @@ -1256,24 +1467,24 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inContext: .single(.wasmFunction), provides: [.wasmFunction] ) { b in - let args = b.randomWasmBlockArguments(upTo: 5) + let args = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) let parameters = args.map(b.type) let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) - let signature = parameters => outputTypes - b.emit(WasmBeginBlock(with: signature), withInputs: args) + let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) + b.runtimeData.push("blockSignature", signature) + b.emit( + WasmBeginBlock(parameterCount: parameters.count), withInputs: [signature] + args + ) }, - GeneratorStub( - "WasmEndBlockGenerator", - inContext: .single(.wasmFunction) - ) { b in - let signature = b.currentWasmSignature + GeneratorStub("WasmEndBlockGenerator", inContext: .single(.wasmFunction)) { b in + let signature = b.runtimeData.pop("blockSignature") + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature let function = b.currentWasmFunction - let outputs = signature.outputTypes.map( - function.findOrGenerateWasmVar) + let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) b.emit( - WasmEndBlock(outputTypes: signature.outputTypes), - withInputs: outputs) + WasmEndBlock(outputCount: wasmSignature.outputTypes.count), + withInputs: [signature] + outputs) }, ]), @@ -1288,10 +1499,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let function = b.currentWasmModule.currentWasmFunction let loopCtr = function.consti32(10) b.runtimeData.push("loopCounter", loopCtr) - b.emit(WasmBeginLoop(with: [] => [])) + let signature = b.wasmDefineAdHocSignatureType(signature: [] => []) + b.runtimeData.push("loopSignature", signature) + 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( @@ -1302,113 +1515,79 @@ 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(outputTypes: [])) + b.emit( + WasmEndLoop(outputCount: 0), withInputs: [b.runtimeData.pop("loopSignature")]) }, ]), - CodeGenerator("WasmLoopWithSignatureGenerator", inContext: .single(.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) - let randomArgTypes = randomArgs.map { b.type(of: $0) } - let args = [function.consti32(0)] + randomArgs - let parameters = args.map(b.type) - let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) - // Note that due to the do-while style implementation, the actual iteration count is at least 1. - let iterationCount = Int32.random(in: 0...16) - - function.wasmBuildLoop(with: parameters => outputTypes, args: args) { - label, loopArgs in - b.buildRecursive(n: defaultCodeGenerationAmount) - let loopCtr = function.wasmi32BinOp( - args[0], function.consti32(1), binOpKind: .Add) - let condition = function.wasmi32CompareOp( - loopCtr, function.consti32(iterationCount), using: .Lt_s) - let backedgeArgs = - [loopCtr] + randomArgTypes.map { b.randomVariable(ofType: $0)! } - function.wasmBranchIf( - condition, to: label, args: backedgeArgs, - hint: b.randomWasmBranchHint()) - return outputTypes.map(function.findOrGenerateWasmVar) - } - }, - - // TODO Turn this into a multi-part Generator - CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { - b in - let function = b.currentWasmModule.currentWasmFunction - // Choose a few random wasm values as arguments if available. - let args = b.randomWasmBlockArguments(upTo: 5) - let parameters = args.map(b.type) - let tags = (0.. [], args: args) { - label, args in - b.buildRecursive(n: 4) - for (i, tag) in tags.enumerated() { - function.WasmBuildLegacyCatch(tag: tag) { _, _, _ in - b.buildRecursive(n: 4) - } - } - } catchAllBody: { label in - b.buildRecursive(n: 4) - } - }, - CodeGenerator( - "WasmLegacyTryCatchWithResultGenerator", inContext: .single(.wasmFunction) - ) { b in - let function = b.currentWasmModule.currentWasmFunction - // Choose a few random wasm values as arguments if available. - let args = b.randomWasmBlockArguments(upTo: 5) - let parameters = args.map(b.type) - let tags = (0.. outputTypes - let recursiveCallCount = 2 + tags.count - function.wasmBuildLegacyTryWithResult( - with: signature, args: args, - body: { label, args in - b.buildRecursive(n: 4) - return outputTypes.map(function.findOrGenerateWasmVar) + "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)) }, - catchClauses: tags.enumerated().map { i, tag in - ( - tag, - { _, _, _ in - b.buildRecursive(n: 4) - return outputTypes.map(function.findOrGenerateWasmVar) - } - ) + 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) }, - catchAllBody: { label in - b.buildRecursive(n: 4) - return outputTypes.map(function.findOrGenerateWasmVar) - }) - }, + ]), // TODO split this into a multi-part Generator. - CodeGenerator( - "WasmLegacyTryCatchWithResultGenerator", inContext: .single(.wasmFunction) - ) { b in + CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { b in let function = b.currentWasmModule.currentWasmFunction // Choose a few random wasm values as arguments if available. - let args = b.randomWasmBlockArguments(upTo: 5) + let args = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) let parameters = args.map(b.type) let tags = (0.. outputTypes + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let recursiveCallCount = 2 + tags.count function.wasmBuildLegacyTryWithResult( - with: signature, args: args, + signature: signature, signatureDef: signatureDef, args: args, body: { label, args in b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) @@ -1430,11 +1609,11 @@ 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. - let args = b.randomWasmBlockArguments(upTo: 5) + let args = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) let outputTypes = b.randomWasmBlockOutputTypes(upTo: 3) let parameters = args.map(b.type) function.wasmBuildLegacyTryDelegateWithResult( @@ -1454,22 +1633,24 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inputs: .required(.wasmi32), provides: [.wasmFunction] ) { b, condition in + let signature = b.wasmDefineAdHocSignatureType(signature: [] => []) + b.runtimeData.push("ifSignature", signature) b.emit( WasmBeginIf(hint: b.randomWasmBranchHint()), - withInputs: [condition]) + withInputs: [signature, condition]) }, GeneratorStub( "WasmBeginElseGenerator", inContext: .single(.wasmFunction), provides: [.wasmFunction] ) { b in - b.emit(WasmBeginElse()) + b.emit(WasmBeginElse(), withInputs: [b.runtimeData.peek("ifSignature")]) }, GeneratorStub( "WasmEndIfElseGenerator", inContext: .single(.wasmFunction) ) { b in - b.emit(WasmEndIf()) + b.emit(WasmEndIf(), withInputs: [b.runtimeData.pop("ifSignature")]) }, ]), @@ -1482,14 +1663,16 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inputs: .required(.wasmi32), provides: [.wasmFunction] ) { b, condition in - let args = b.randomWasmBlockArguments(upTo: 5) + let args = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) let parameters = args.map(b.type) let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) + let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) + b.runtimeData.push("ifSignature", signature) b.emit( WasmBeginIf( - with: parameters => outputTypes, + parameterCount: parameters.count, hint: b.randomWasmBranchHint()), - withInputs: args + [condition]) + withInputs: [signature] + args + [condition]) }, GeneratorStub( "WasmBeginElseGenerator", @@ -1497,22 +1680,26 @@ public let WasmCodeGenerators: [CodeGenerator] = [ provides: [.wasmFunction] ) { b in let function = b.currentWasmFunction - let signature = b.currentWasmSignature - let trueResults = signature.outputTypes.map( - function.findOrGenerateWasmVar) - b.emit(WasmBeginElse(with: signature), withInputs: trueResults) + 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), + withInputs: [signature] + trueResults) }, GeneratorStub( "WasmEndIfGenerator", inContext: .single(.wasmFunction) ) { b in let function = b.currentWasmFunction - let signature = b.currentWasmSignature - let falseResults = signature.outputTypes.map( - function.findOrGenerateWasmVar) + let signature = b.runtimeData.pop("ifSignature") + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature + let falseResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) b.emit( - WasmEndIf(outputTypes: signature.outputTypes), - withInputs: falseResults) + WasmEndIf(outputCount: wasmSignature.outputTypes.count), + withInputs: [signature] + falseResults) }, ]), @@ -1547,31 +1734,73 @@ 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) }, + 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) + inputs: .required(.wasmExnRef()) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction function.wasmBuildThrowRef(exception: exception) }, + CodeGenerator( + "WasmAdHocModuleSignature", + inContext: .single(.wasm), + producesComplex: [.init(.wasmTypeDef(), .IsWasmFunction)] + ) { b in + let (signature, indexTypes) = b.randomWasmGcSignature() + b.wasmDefineAdHocSignatureType(signature: signature, indexTypes: indexTypes) + }, + CodeGenerator( "WasmDefineTagGenerator", inContext: .single(.wasm), produces: [.object(ofGroup: "WasmTag")] ) { b in - b.currentWasmModule.addTag(parameterTypes: b.randomTagParameters()) + // TODO(mliedtke): If we allow non-nullable reference types in signatures, we'll also need + // to be able to provide valid values for them when trying to throw an instance of this tag. + let (signature, indexTypes) = + b.randomWasmGcSignature(withResults: false, allowNonNullable: false) + let signatureDef = + b.wasmDefineAdHocSignatureType(signature: signature, indexTypes: indexTypes) + b.currentWasmModule.addTag(signature: signatureDef) }, 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( @@ -1581,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( @@ -1599,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) @@ -1607,18 +1836,20 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let extraBlockCount = Int.random(in: 1...5) let valueCount = Int.random(in: 0...20) let signature = [] => parameterTypes + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) (0.. outputTypes, args: []) - return outputTypes + let signature = [] => outputTypes + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + b.emit(WasmBeginBlock(parameterCount: 0), withInputs: [signatureDef]) + return signatureDef } // Look up the labels. In most cases these will be exactly the ones produced by the blocks // above but also any other matching existing block could be used. (Similar, tags with the // same parameter types could also be mapped to the same block.) - let labels = outputTypesList.map { outputTypes in - b.randomVariable(ofType: .label(outputTypes))! + let labels = signatureDefs.map { signatureDef in + b.randomVariable( + ofType: .wasmLabel( + b.type(of: signatureDef).wasmFunctionSignatureDefSignature.outputTypes))! } let catches = zip(tags, withExnRef).map { tag, withExnRef -> WasmBeginTryTable.CatchKind in @@ -1669,7 +1907,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ : (withExnRef ? .Ref : .NoRef) } - var tryArgs = b.randomWasmBlockArguments(upTo: 5) + var tryArgs = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) let tryParameters = tryArgs.map { b.type(of: $0) } let tryOutputTypes = b.randomWasmBlockOutputTypes(upTo: 5) tryArgs += zip(tags, labels).map { tag, label in @@ -1682,12 +1920,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.buildRecursive(n: defaultCodeGenerationAmount) return tryOutputTypes.map(function.findOrGenerateWasmVar) } - outputTypesList.reversed().enumerated().forEach { - n, outputTypes in - let results = outputTypes.map( - function.findOrGenerateWasmVar) - function.wasmEndBlock( - outputTypes: outputTypes, args: results) + 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.buildRecursive(n: defaultCodeGenerationAmount) } } @@ -1736,13 +1974,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) }, @@ -1776,13 +2018,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) }, @@ -1879,4 +2125,102 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // Then we need a WasmJsCallSuspendingFunctionGenerator that takes such a WasmSuspenderObject function, unpacks the signature and emits a WasmJsCall // Then we also need a WrapPromisingGenerator that requires a WebAssembly module object, gets the exports field and its methods and then wraps one of those. // For all of this to work we need to add a WasmTypeExtension and ideally the dynamic object group inference. + + CodeGenerator( + "WasmMemoryToResizableBufferGenerator", + inContext: .single(.javascript), + inputs: .required(.object(ofGroup: "WasmMemory")), + produces: [.jsArrayBuffer | .jsSharedArrayBuffer] + ) { b, memory in + b.callMethod("toResizableBuffer", on: memory) + }, + + CodeGenerator( + "WasmMemoryToFixedLengthBufferGenerator", + inContext: .single(.javascript), + inputs: .required(.object(ofGroup: "WasmMemory")), + produces: [.jsArrayBuffer | .jsSharedArrayBuffer] + ) { b, memory in + b.callMethod("toFixedLengthBuffer", on: memory) + }, + + CodeGenerator( + "WasmMemoryJSGrowGenerator", + inContext: .single(.javascript), + inputs: .required(.object(ofGroup: "WasmMemory")) + ) { b, memory in + b.callMethod("grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...10))]) + }, ] + +private let wasmArrayTypeGenerator = GeneratorStub( + "WasmArrayTypeGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [.init(.wasmTypeDef(), .IsWasmArray)] +) { b in + let mutability = probability(0.75) + if let elementType = b.randomVariable(ofType: .wasmTypeDef()), + probability(0.25) + { + // Excluding non-nullable references from referring to a self-reference ensures we do not end up with cycles of non-nullable references. + let nullability = + b.type(of: elementType).wasmTypeDefinition!.description + == .selfReference || probability(0.5) + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: nullability), + 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()) + }), + mutability: mutability) + } +} + +private let wasmStructTypeGenerator = GeneratorStub( + "WasmStructTypeGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)] +) { b in + + let (fields, indexTypes) = b.generateRandomWasmStructFields() + + b.wasmDefineStructType(fields: fields, indexTypes: indexTypes) +} + +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.. Variable { - // The expressions for property values and computed properties need to be emitted before the class declaration is opened. + private func compileClass( + _ name: String, superClass: ExpressionNode?, fields: [ClassFieldNode], isExpression: Bool + ) throws -> Variable { + // 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") } - 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): + 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(let constructor): + defaultValuesPerSubroutine.append( + try compileDefaultValues(for: constructor.parameters)) + key = nil + case .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)) } } // 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 { 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)) } @@ -117,24 +137,16 @@ 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()) @@ -142,8 +154,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 @@ -157,6 +171,7 @@ public class JavaScriptCompiler { emit(EndClassConstructor()) case .method(let method): + let defaultValues = defaultValuesPerSubroutine.removeLast() let parameters = convertParameters(method.parameters) let head: Instruction @@ -165,19 +180,20 @@ 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)) - } - case .index: - throw CompilerError.invalidNodeError("Not supported") + head = emit( + BeginClassMethod( + methodName: name, parameters: parameters, isStatic: method.isStatic), + withInputs: defaultValues) + case .index(let index): + head = emit( + BeginClassMethod( + methodName: String(index), parameters: parameters, + isStatic: method.isStatic), + withInputs: defaultValues) 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()] + defaultValues) } try enterNewScope { @@ -191,27 +207,28 @@ public class JavaScriptCompiler { switch key { case .name: - if method.isStatic { - emit(EndClassStaticMethod()) - } else { - emit(EndClassInstanceMethod()) - } + emit(EndClassMethod()) case .index: - throw CompilerError.invalidNodeError("Not supported") + 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)) + 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 { @@ -221,33 +238,45 @@ public class JavaScriptCompiler { } } - if getter.isStatic { - emit(EndClassStaticGetter()) - } else { - emit(EndClassInstanceGetter()) + switch key { + case .name, .index: + emit(EndClassGetter()) + case .expression: + emit(EndClassComputedGetter()) } case .setter(let setter): let head: Instruction - if setter.isStatic { - head = emit(BeginClassStaticSetter(propertyName: setter.name)) - } else { - head = emit(BeginClassInstanceSetter(propertyName: setter.name)) + 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 map("this", to: parameters.removeFirst()) - mapParameters([setter.parameter], to: parameters) + map(setter.parameter.name, to: parameters.removeFirst()) + assert(parameters.isEmpty) for statement in setter.body { try compileStatement(statement) } } - if setter.isStatic { - emit(EndClassStaticSetter()) - } else { - emit(EndClassInstanceSetter()) + switch key { + case .name, .index: + emit(EndClassSetter()) + case .expression: + emit(EndClassComputedSetter()) } case .staticInitializer(let staticInitializer): @@ -269,7 +298,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 { @@ -310,10 +341,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) @@ -323,40 +358,53 @@ 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) } case .functionDeclaration(let functionDeclaration): + let defaultValues = try compileDefaultValues(for: functionDeclaration.parameters) 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)") } - 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) @@ -370,7 +418,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 { @@ -440,7 +490,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) @@ -449,10 +500,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 { @@ -461,9 +515,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) } @@ -472,16 +530,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) @@ -495,9 +554,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) @@ -511,9 +571,9 @@ public class JavaScriptCompiler { emit(EndForOfLoop()) case .breakStatement: - // If we're in both .loop and .switch context, then the loop must be the most recent context + // 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()) @@ -565,14 +625,14 @@ public class JavaScriptCompiler { emit(EndWith()) case .switchStatement(let switchStatement): // TODO Replace the precomputation of tests with compilation of the test expressions in the cases. - // To do this, we would need to redesign Switch statements in FuzzIL to (for example) have a BeginSwitchCaseHead, BeginSwitchCaseBody, and EndSwitchCase. + // To do this, we would need to redesign Switch statements in FuzzIL to (for example) have a BeginSwitchCaseHead, BeginSwitchCaseBody, and EndSwitchCase. // Then the expression would go inside the header. var precomputedTests = [Variable]() for caseStatement in switchStatement.cases { if caseStatement.hasTest { let test = try compileExpression(caseStatement.test) precomputedTests.append(test) - } + } } let discriminant = try compileExpression(switchStatement.discriminant) emit(BeginSwitch(), withInputs: [discriminant]) @@ -589,7 +649,7 @@ public class JavaScriptCompiler { } // We could also do an optimization here where we check if the last statement in the case is a break, and if so, we drop the last instruction // and set the fallsThrough flag to false. - emit(EndSwitchCase(fallsThrough: true)) + emit(EndSwitchCase(fallsThrough: true)) } emit(EndSwitch()) } @@ -620,7 +680,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) @@ -652,7 +714,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" { @@ -680,7 +742,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): @@ -689,7 +754,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): @@ -726,7 +792,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 } @@ -735,25 +802,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]) } @@ -762,18 +841,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]) @@ -788,7 +871,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 { @@ -800,48 +885,61 @@ 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 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("missing concrete field in object expression") + throw CompilerError.invalidNodeError( + "missing concrete field in object expression") } - if case .property(let property) = field { + + let key: Compiler_Protobuf_PropertyKey + switch field { + case .property(let property): 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)) - } + key = property.key + case .method(let method): + methodDefaultValues.append(try compileDefaultValues(for: method.parameters)) + 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)) } } // 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()) for field in objectExpression.fields { switch field.field! { case .property(let property): - guard let key = property.key else { - throw CompilerError.invalidNodeError("missing key in object expression field") + guard let key = property.key.body else { + throw CompilerError.invalidNodeError( + "missing key in object expression field") } let inputs = [propertyValues.removeLast()] switch key { @@ -850,20 +948,37 @@ 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 defaultValues = methodDefaultValues.removeLast() 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), + withInputs: defaultValues) + case .index(let index): + head = emit( + BeginObjectLiteralMethod( + methodName: String(index), parameters: parameters), + withInputs: defaultValues) + case .expression: + head = emit( + BeginObjectLiteralComputedMethod(parameters: parameters), + withInputs: [computedKeys.removeLast()] + defaultValues) } 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 { @@ -871,37 +986,71 @@ 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 { - fatalError("Computed getters are not yet supported") + 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: + head = emit( + BeginObjectLiteralComputedGetter(), + withInputs: [computedKeys.removeLast()]) } - 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()) + switch key { + case .name, .index: + emit(EndObjectLiteralGetter()) + case .expression: + emit(EndObjectLiteralComputedGetter()) + } case .setter(let setter): - guard case .name(let name) = setter.key else { - fatalError("Computed setters are not yet supported") + 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: + head = emit( + BeginObjectLiteralComputedSetter(), + withInputs: [computedKeys.removeLast()]) } - let instr = emit(BeginObjectLiteralSetter(propertyName: name)) try enterNewScope { - var parameters = instr.innerOutputs + var parameters = head.innerOutputs map("this", to: parameters.removeFirst()) - mapParameters([setter.parameter], to: parameters) + map(setter.parameter.name, to: parameters.removeFirst()) + assert(parameters.isEmpty) for statement in setter.body { try compileStatement(statement) } } - emit(EndObjectLiteralSetter()) + switch key { + case .name, .index: + emit(EndObjectLiteralSetter()) + case .expression: + emit(EndObjectLiteralComputedSetter()) + } } } return emit(EndObjectLiteral()).output @@ -930,12 +1079,15 @@ 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 defaultValues = try compileDefaultValues(for: functionExpression.parameters) 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: @@ -948,13 +1100,14 @@ 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)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) try enterNewScope { mapParameters(functionExpression.parameters, to: instr.innerOutputs) for statement in functionExpression.body { @@ -966,8 +1119,10 @@ public class JavaScriptCompiler { return instr.output case .arrowFunctionExpression(let arrowFunction): + let defaultValues = try compileDefaultValues(for: arrowFunction.parameters) let parameters = convertParameters(arrowFunction.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation switch arrowFunction.type { case .plain: functionBegin = BeginArrowFunction(parameters: parameters) @@ -976,13 +1131,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) + let instr = emit(functionBegin, withInputs: defaultValues) 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) @@ -1003,47 +1161,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") } - 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 + 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 } 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 } } @@ -1052,43 +1260,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") @@ -1099,8 +1330,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 @@ -1115,8 +1349,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) @@ -1156,7 +1394,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 @@ -1174,7 +1413,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): @@ -1186,7 +1426,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 @@ -1207,15 +1448,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 } } @@ -1226,12 +1470,12 @@ public class JavaScriptCompiler { let outputs = (0.. ()) rethrows { + private func enterNewScope(_ block: () throws -> Void) rethrows { scopes.push([:]) try block() scopes.pop() @@ -1251,15 +1495,35 @@ public class JavaScriptCompiler { scopes.top[identifier] = v } - private func mapParameters(_ parameters: [Compiler_Protobuf_Parameter], to variables: ArraySlice) { - assert(parameters.count == variables.count) - for (param, v) in zip(parameters, variables) { + 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) } } - private func convertParameters(_ parameters: [Compiler_Protobuf_Parameter]) -> Parameters { - return Parameters(count: parameters.count) + 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, + defaultParameterIndices: defaultParameterIndices) } /// Convenience accessor for the currently active scope. @@ -1296,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/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/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 081449c34..c1cba8b76 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -36,6 +36,17 @@ function tryReadFile(path) { function parse(script, proto) { let ast = Parser.parse(script, { plugins: ["explicitResourceManagement", "v8intrinsic"] }); + // We assume leading comments (and whitespace) until the starting + // character of the first node of the program. This way + // is easier than rebuilding the comments from Babel's + // `leadingComments` AST nodes, which don't include whitespace and + // newlines. + const firstNode = ast.program.body[0]; + let leadingComments = ''; + if (firstNode) { + leadingComments = script.substring(0, firstNode.start); + } + function assertNoError(err) { if (err) throw err; } @@ -46,7 +57,7 @@ function parse(script, proto) { function visitProgram(node) { const AST = proto.lookupType('compiler.protobuf.AST'); - let program = {statements: []}; + let program = {leadingComments: leadingComments, statements: []}; for (let child of node.body) { program.statements.push(visitStatement(child)); } @@ -73,13 +84,28 @@ function parse(script, proto) { } function visitParameter(param) { - assert(param.type == 'Identifier', "Expected parameter type to have type 'Identifier', found " + param.type); - return make('Parameter', { name: param.name }); + 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: + assert(false, "Unknown parameter type: " + param.type); + } } function visitParameters(params) { - return params.map(visitParameter) - } + return make('Parameters', { + parameters: params.map(visitParameter), + hasRestElement: params.some(param => param.type === 'RestElement'), + }); + }; // Processes the body of a block statement node and returns a list of statements. function visitBody(node) { @@ -144,7 +170,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); @@ -194,26 +220,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; } @@ -448,19 +470,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'"); @@ -469,12 +479,7 @@ function parse(script, proto) { let method = field; let out = {}; - if (method.computed) { - out.expression = visitExpression(method.key); - } else { - assert(method.key.type === 'Identifier', "Expected method.key.type to be exactly 'Identifier'") - out.name = method.key.name; - } + out.key = visitMemberKey(method); field = {}; if (method.kind === 'method') { @@ -667,7 +672,7 @@ protobuf.load(astProtobufDefinitionPath, function(err, root) { if (err) throw err; - let ast = parse(script, root); + const ast = parse(script, root); // Uncomment this to print the AST to stdout (will be very verbose). //console.log(JSON.stringify(ast, null, 2)); diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 121e9cbb8..efd048ddf 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -12,7 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO(mdanylo): this should be part of the protocol between Fuzzilli and V8. +public struct DifferentialConfig { + public let dumpFilenamePattern: String + + public init(dumpFilenamePattern: String) { + self.dumpFilenamePattern = dumpFilenamePattern + } + + public func getDumpFilename(isOptimized: Bool) -> String { + let subDirectory = isOptimized ? "optimizedDump" : "unoptimizedDump" + return String(format: dumpFilenamePattern, subDirectory) + } + + public func getDumpFilenameParameter(isOptimized: Bool) -> String { + return "--dump-out-filename=\(getDumpFilename(isOptimized: isOptimized))" + } + + public static func create(for instanceId: Int, storagePath: String) -> DifferentialConfig { + // TODO(mdanylo): it would be cool to add random hash to the filename if we store dumps + // in the filesystem for debugging. + let fileName = "output_dump_\(instanceId).txt" + let pattern = "\(storagePath)/%@/\(fileName)" + return DifferentialConfig(dumpFilenamePattern: pattern) + } +} + public struct Configuration { + /// The config specific to differential fuzzing + public let diffConfig: DifferentialConfig? + /// The commandline arguments used by this instance. public let arguments: [String] @@ -68,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). @@ -77,21 +110,30 @@ 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) { + // Whether the fuzzer generates bundles containing multiple JavaScript scripts or modules. + public let generateBundle: Bool + + 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, + generateBundle: Bool = false, + storagePath: String? = nil, + corpusGenerationIterations: Int = 100, + forDifferentialFuzzing: Bool = false, + instanceId: Int = -1, + dumplingEnabled: Bool = false + ) { self.arguments = arguments self.timeout = timeout self.logLevel = logLevel @@ -104,8 +146,18 @@ public struct Configuration { self.staticCorpus = staticCorpus self.tag = tag self.isWasmEnabled = isWasmEnabled + self.generateBundle = generateBundle self.storagePath = storagePath + self.corpusGenerationIterations = corpusGenerationIterations self.forDifferentialFuzzing = forDifferentialFuzzing + self.diffConfig = + dumplingEnabled + ? DifferentialConfig.create(for: instanceId, storagePath: storagePath!) : nil + } + + public func getInstanceSpecificArguments(forReferenceRunner: Bool) -> [String] { + 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..2224f593c 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 @@ -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") } @@ -137,7 +138,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 new file mode 100644 index 000000000..430169bb2 --- /dev/null +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -0,0 +1,288 @@ +// 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. + +// The tool implemented in this file compares two Dumpling dumps for +// equality. Each Dumpling dump consists of multiple frame dumps. +// Example frame dump: +// ---I +// b:34 +// f:500 +// n:3 +// m:5 +// x:40 +// r0:30 +// r3:some_string +// a0:1 +// a1:2 +// +// A frame dump always starts with a header which is one of +// ---I (for interpreter), ---S (for Sparkplug), ---M (for Maglev), +// ---T (for Turbofan), ---D (deopt Turbofan: this is frame produced by actual +// Turbofan deopt, not by Dumpling). +// Next line with 'b' might follow (see when it and other lines might get omitted +// in the NOTE below), it denotes bytecode offset of a dump (within a function). +// Next line with 'f' might follow, it denotes JS function id of a dump. +// Next line with 'x' might follow, it denotes the dump of the accumulator. +// Next lines with 'n' and 'm' might follow, which denote parameters of a function +// and register count of a frame respectfully. +// Next multiple lines 'ai' might follow, where 'a' denotes that this is a dump +// of a function parameter and 'i' denotes the number of the parameter. +// Next multiple lines 'ri' might follow, where 'r' denotes that this is a dump +// of a register and 'i' denotes the number of the register. +// Lastly an empty line always ends the frame dump. +// +// NOTE: frame dumps are implemented incrementally to not write too much data +// to the file. +// IOW let's say we dumped 2 frames with full format as follows: +// ---I +// b:30 +// f:40 +// a0:1 +// a1:2 +// +// ---I +// b:35 +// f:40 +// a0:1 +// a1:1 +// +// In order to save space a file will contain just: +// ---I +// b:30 +// f:40 +// a0:1 +// a1:2 +// +// ---I +// b:35 +// a1:1 + +import Foundation + +// This class is implementing one public function relate(optimizedOutput, unoptimizedOutput). +// `relate` compares optimizedOutput and unoptimizedOutput for equality. +public final class DiffOracle { + private enum FrameType { + case interpreter + case sparkplug + case maglev + case turbofan + case deoptTurbofan + } + + private struct Frame: Equatable, CustomStringConvertible { + let bytecodeOffset: Int + let accumulator: String + let arguments: [String] + let registers: [String] + let functionId: Int + let frameType: FrameType + + // This is only needed for debug output. + var description: String { + var lines: [String] = [] + + lines.append("") + lines.append("╔══════════════════════════════════════") + lines.append("║ Frame: \(frameType) (FuncID: \(functionId), Offset: \(bytecodeOffset))") + lines.append("╠══════════════════════════════════════") + lines.append("║ Accumulator: \(accumulator)") + + if arguments.isEmpty { + lines.append("║ Arguments: []") + } else { + lines.append("║ Arguments:") + for (index, arg) in arguments.enumerated() { + lines.append("║ [\(index)] \(arg)") + } + } + + if registers.isEmpty { + lines.append("║ Registers: []") + } else { + lines.append("║ Registers:") + for (index, reg) in registers.enumerated() { + lines.append("║ [\(index)] \(reg)") + } + } + + lines.append("╚══════════════════════════════════════") + + return lines.joined(separator: "\n") + } + + // 'reference' is the value from Unoptimized frame. + func matches(reference: Frame) -> Bool { + + guard self.bytecodeOffset == reference.bytecodeOffset, + self.functionId == reference.functionId, + self.arguments.count == reference.arguments.count, + 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 + } + + if !isMatch(self.accumulator, unoptValue: reference.accumulator) { + return false + } + + if !zip(self.arguments, reference.arguments).allSatisfy(isMatch) { + return false + } + + if !zip(self.registers, reference.registers).allSatisfy(isMatch) { + return false + } + + return true + } + } + + private static func parseDiffFrame( + _ frameArr: ArraySlice, + _ prevFrame: Frame?, + _ runningArgs: inout [String], + _ runningRegs: inout [String] + ) -> Frame { + + 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 + return value + } + return defaultValue + } + 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") + } + } + + let frameType: FrameType = parseFrameType(frameArr[i]) + + 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)! } + + func updateValues(prefix: String, requiredCount: Int, buffer: inout [String]) -> [String] { + + if buffer.count < requiredCount { + let missingCount = requiredCount - buffer.count + let defaults = Array(repeating: "", count: missingCount) + buffer.append(contentsOf: defaults) + } + + while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { + let data = frameArr[i].dropFirst(1).split( + separator: ":", maxSplits: 1, omittingEmptySubsequences: false) + let number = Int(data[0])! + let value = String(data[1]) + + buffer[number] = value + i += 1 + } + + return Array(buffer.prefix(requiredCount)) + } + + 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) + return frame + } + + private static func parseFullFrames(_ stdout: String) -> [Frame] { + var frameArray: [Frame] = [] + var prevFrame: Frame? = nil + + var runningArgs: [String] = [] + var runningRegs: [String] = [] + + let split = stdout.split(separator: "\n", omittingEmptySubsequences: false) + let frames = split.split(separator: "") + + for frame in frames { + assert( + frame.first?.starts(with: "---") == true, + "Invalid frame header found: \(frame.first ?? "nil")") + + prevFrame = parseDiffFrame(frame, prevFrame, &runningArgs, &runningRegs) + frameArray.append(prevFrame!) + } + return frameArray + } + + public static func relate(_ optIn: String, with unoptIn: String) -> Bool { + let optFrames = parseFullFrames(optIn) + let unoptFrames = parseFullFrames(unoptIn) + var unoptFramesLeft = ArraySlice(unoptFrames) + + for optFrame in optFrames { + guard let unoptIndex = unoptFramesLeft.firstIndex(where: optFrame.matches) else { + print(optFrame) + print("--------------------------") + print("[") + for unoptFrame in unoptFrames { + if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset + && unoptFrame.functionId == optFrame.functionId + { + print(unoptFrame) + } + } + print("]") + return false + } + // Remove all skipped frames but keep the found frame, because we might have multiple deopt points on same offset. + unoptFramesLeft = unoptFramesLeft[unoptIndex...] + } + return true + } +} diff --git a/Sources/Fuzzilli/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift index 815caad30..191c613cf 100644 --- a/Sources/Fuzzilli/Engines/FuzzEngine.swift +++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift @@ -32,45 +32,67 @@ public class FuzzEngine: ComponentBase { fatalError("Must be implemented by child classes") } - final func execute(_ program: Program, withTimeout timeout: UInt32? = nil) -> ExecutionOutcome { - let program = postProcessor?.process(program, for: fuzzer) ?? 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. + program = try postProcessor?.process(rawProgram, for: fuzzer) ?? rawProgram + } catch InternalError.postProcessRejection { + return ExecutionOutcome.failed(1) + } catch { + fatalError("Unexpected error in post processor.") + } fuzzer.dispatchEvent(fuzzer.events.ProgramGenerated, data: program) 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 .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) - } - - if isInteresting { - program.contributors.generatedInterestingSample() - } else { - program.contributors.generatedValidSample() + 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) } - - 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 { @@ -83,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/FuzzingPostProcessor.swift b/Sources/Fuzzilli/Engines/FuzzingPostProcessor.swift index e0c61f27f..11787779e 100644 --- a/Sources/Fuzzilli/Engines/FuzzingPostProcessor.swift +++ b/Sources/Fuzzilli/Engines/FuzzingPostProcessor.swift @@ -16,5 +16,5 @@ import Foundation // A post-processor can be used to modify samples generated during fuzzing before executing them. public protocol FuzzingPostProcessor { - func process(_ program: Program, for fuzzer: Fuzzer) -> Program + func process(_ program: Program, for fuzzer: Fuzzer) throws -> Program } 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/Engines/HybridEngine.swift b/Sources/Fuzzilli/Engines/HybridEngine.swift index b59aa1ed4..3c57b68f4 100644 --- a/Sources/Fuzzilli/Engines/HybridEngine.swift +++ b/Sources/Fuzzilli/Engines/HybridEngine.swift @@ -21,6 +21,7 @@ public class HybridEngine: FuzzEngine { // The different outcomes of one fuzzing iterations. private enum CodeGenerationOutcome: String, CaseIterable { case success = "Success" + case generatedCodeDifferential = "Generated code differential" case generatedCodeFailed = "Generated code failed" case generatedCodeTimedOut = "Generated code timed out" case generatedCodeCrashed = "Generated code crashed" @@ -56,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, +) @@ -68,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))%" + ) } } } @@ -98,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. @@ -112,6 +127,8 @@ public class HybridEngine: FuzzEngine { return recordOutcome(.generatedCodeTimedOut) case .crashed: return recordOutcome(.generatedCodeCrashed) + case .differential: + return recordOutcome(.generatedCodeDifferential) } // Now perform one round of fixup to improve the generated program based on runtime information and in particular remove all try-catch guards that are not needed. @@ -122,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 @@ -152,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 17888b9f1..bb2429870 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -16,282 +16,306 @@ 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 = [ + "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", + "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", + "Uint8ClampedArray", "BigInt64Array", "BigUint64Array", + ] // 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 + -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 + public let interestingStrings = jsTypeNames + [""] // Copied from // 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 = ["*", "+", "?"] /// 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 CustomMethodNames = ["m", "n", "o", "p", "valueOf", "toString"] + 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"] public private(set) var builtins = Set() public let customProperties = Set(CustomPropertyNames) public let customMethods = Set(CustomMethodNames) + public let customPrivateMethods = Set(CustomPrivateMethodNames) public private(set) var builtinProperties = Set() public private(set) var builtinMethods = Set() - // Something that can generate a variable public typealias EnvironmentValueGenerator = (ProgramBuilder) -> Variable @@ -300,14 +324,42 @@ 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)]] = [:] private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] - 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). + static let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" + + // A non-negative integer (with no leading zero) for index access + // without quotes. + 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. + 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. + static let dotNotationName = try! Regex("^(\(simpleId))$") + + // Valid indexes to use in bracket notation without quotes. + static let propertyIndex = try! Regex("^(\(index))$") + } + + public init( + additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], + additionalEnumerations: [ILType] = [] + ) { + super.init(name: "JavaScriptEnvironment") // Build model of the JavaScript environment @@ -322,37 +374,70 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsStrings) registerObjectGroup(.jsArrays) registerObjectGroup(.jsArguments) + registerObjectGroup(.jsIterator) + registerObjectGroup(.jsIteratorPrototype) + registerObjectGroup(.jsIteratorConstructor) registerObjectGroup(.jsGenerators) registerObjectGroup(.jsPromises) registerObjectGroup(.jsRegExps) registerObjectGroup(.jsFunctions) + registerObjectGroup(.jsFunctionPrototype) + registerObjectGroup(.jsFunctionConstructor) registerObjectGroup(.jsSymbols) registerObjectGroup(.jsMaps) + registerObjectGroup(.jsMapPrototype) + registerObjectGroup(.jsMapConstructor) registerObjectGroup(.jsWeakMaps) + registerObjectGroup(.jsWeakMapPrototype) + registerObjectGroup(.jsWeakMapConstructor) registerObjectGroup(.jsSets) + registerObjectGroup(.jsSetPrototype) + registerObjectGroup(.jsSetConstructor) registerObjectGroup(.jsWeakSets) + registerObjectGroup(.jsWeakSetPrototype) + registerObjectGroup(.jsWeakSetConstructor) registerObjectGroup(.jsWeakRefs) + registerObjectGroup(.jsWeakRefPrototype) + registerObjectGroup(.jsWeakRefConstructor) registerObjectGroup(.jsFinalizationRegistrys) + registerObjectGroup(.jsFinalizationRegistryPrototype) + registerObjectGroup(.jsFinalizationRegistryConstructor) + registerObjectGroup(.jsDisposableStacks) + registerObjectGroup(.jsDisposableStackPrototype) + registerObjectGroup(.jsDisposableStackConstructor) + registerObjectGroup(.jsAsyncDisposableStacks) + registerObjectGroup(.jsAsyncDisposableStackPrototype) + registerObjectGroup(.jsAsyncDisposableStackConstructor) registerObjectGroup(.jsArrayBuffers) registerObjectGroup(.jsSharedArrayBuffers) - for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "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)) } - registerObjectGroup(.jsUint8ArrayConstructor) - registerObjectGroup(.jsUint8ArrayPrototype) registerObjectGroup(.jsDataViews) + registerObjectGroup(.jsDataViewPrototype) + registerObjectGroup(.jsDataViewConstructor) registerObjectGroup(.jsObjectConstructor) registerObjectGroup(.jsPromiseConstructor) registerObjectGroup(.jsPromisePrototype) + registerObjectGroup(.jsProxyConstructor) registerObjectGroup(.jsArrayConstructor) registerObjectGroup(.jsStringConstructor) registerObjectGroup(.jsStringPrototype) registerObjectGroup(.jsSymbolConstructor) registerObjectGroup(.jsBigIntConstructor) + registerObjectGroup(.jsRegExpPrototype) + registerObjectGroup(.jsRegExpConstructor) registerObjectGroup(.jsBooleanConstructor) registerObjectGroup(.jsNumberConstructor) registerObjectGroup(.jsMathObject) + registerObjectGroup(.jsAtomicsObject) registerObjectGroup(.jsDate) registerObjectGroup(.jsDateConstructor) registerObjectGroup(.jsDatePrototype) @@ -362,8 +447,13 @@ 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)) } registerObjectGroup(.jsWebAssemblyCompileOptions) registerObjectGroup(.jsWebAssemblyModuleConstructor) @@ -381,6 +471,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsWebAssemblyException) registerObjectGroup(.jsWebAssemblyExceptionPrototype) registerObjectGroup(.jsWebAssemblyExceptionConstructor) + registerObjectGroup(.jsWebAssemblyError) + registerObjectGroup(.jsWebAssemblyErrorPrototype) + registerObjectGroup(.jsWebAssemblyErrorConstructor) registerObjectGroup(.jsWebAssembly) registerObjectGroup(.jsWasmGlobal) registerObjectGroup(.jsWasmMemory) @@ -417,12 +510,21 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsIntlCollator) registerObjectGroup(.jsIntlCollatorConstructor) registerObjectGroup(.jsIntlCollatorPrototype) + registerObjectGroup(.jsIntlDisplayNames) + registerObjectGroup(.jsIntlDisplayNamesConstructor) + registerObjectGroup(.jsIntlDisplayNamesPrototype) + registerObjectGroup(.jsIntlDurationFormat) + registerObjectGroup(.jsIntlDurationFormatConstructor) + registerObjectGroup(.jsIntlDurationFormatPrototype) registerObjectGroup(.jsIntlDateTimeFormat) registerObjectGroup(.jsIntlDateTimeFormatConstructor) registerObjectGroup(.jsIntlDateTimeFormatPrototype) registerObjectGroup(.jsIntlListFormat) registerObjectGroup(.jsIntlListFormatConstructor) registerObjectGroup(.jsIntlListFormatPrototype) + registerObjectGroup(.jsIntlLocale) + registerObjectGroup(.jsIntlLocaleConstructor) + registerObjectGroup(.jsIntlLocalePrototype) registerObjectGroup(.jsIntlNumberFormat) registerObjectGroup(.jsIntlNumberFormatConstructor) registerObjectGroup(.jsIntlNumberFormatPrototype) @@ -466,8 +568,13 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlFullLongMediumShort) registerEnumeration(OptionsBag.jsIntlCollatorUsageEnum) registerEnumeration(OptionsBag.jsIntlCollationEnum) + registerEnumeration(OptionsBag.jsIntlCollationTypeEnum) registerEnumeration(OptionsBag.jsIntlCaseFirstEnum) registerEnumeration(OptionsBag.jsIntlCollatorSensitivityEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesTypeEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesFallbackEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesLanguageDisplayEnum) + registerEnumeration(OptionsBag.jsIntlDurationFormatStyleEnum) registerEnumeration(OptionsBag.jsIntlListFormatTypeEnum) registerEnumeration(OptionsBag.jsIntlNumberFormatStyleEnum) registerEnumeration(OptionsBag.jsIntlCurrencySystemEnum) @@ -481,6 +588,7 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlSignDisplayEnum) registerEnumeration(OptionsBag.jsIntlPluralRulesTypeEnum) registerEnumeration(OptionsBag.jsIntlSegmenterGranularityEnum) + registerEnumeration(OptionsBag.jsIteratorZipModeEnum) registerEnumeration(OptionsBag.base64Alphabet) registerEnumeration(OptionsBag.base64LastChunkHandling) @@ -500,47 +608,91 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsTemporalPlainDateToZDTSettings) registerOptionsBag(.jsIntlDateTimeFormatSettings) registerOptionsBag(.jsIntlCollatorSettings) + registerOptionsBag(.jsIntlDisplayNamesSettings) + registerOptionsBag(.jsIntlDurationFormatSettings) registerOptionsBag(.jsIntlListFormatSettings) + registerOptionsBag(.jsIntlLocaleSettings) registerOptionsBag(.jsIntlNumberFormatSettings) registerOptionsBag(.jsIntlPluralRulesSettings) registerOptionsBag(.jsIntlRelativeTimeFormatSettings) registerOptionsBag(.jsIntlSegmenterSettings) registerOptionsBag(.jsIntlLocaleMatcherSettings) - - 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) + 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) // 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: .jsIntlLocaleLike, with: { ProgramBuilder.constructIntlLocaleString() }) - addNamedStringGenerator(forType: .jsIntlUnit, 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 @@ -552,19 +704,24 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("Boolean", ofType: .jsBooleanConstructor) registerBuiltin("Number", ofType: .jsNumberConstructor) registerBuiltin("Symbol", ofType: .jsSymbolConstructor) + registerBuiltin("Iterator", ofType: .jsIteratorConstructor) registerBuiltin("BigInt", ofType: .jsBigIntConstructor) registerBuiltin("RegExp", ofType: .jsRegExpConstructor) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError"] { + for variant in [ + "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", + "URIError", "SuppressedError", "AggregateError", + ] { registerBuiltin(variant, ofType: .jsErrorConstructor(variant)) } - registerBuiltin("AggregateError", ofType: .functionAndConstructor([.plain(.iterable), .opt(.string), .opt(.object())] => .jsError("AggregateError"))) registerBuiltin("ArrayBuffer", ofType: .jsArrayBufferConstructor) registerBuiltin("SharedArrayBuffer", ofType: .jsSharedArrayBufferConstructor) - // Uint8Array handled below. - for variant in ["Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "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("Uint8Array", ofType: .jsUint8ArrayConstructor) registerBuiltin("DataView", ofType: .jsDataViewConstructor) registerBuiltin("Date", ofType: .jsDateConstructor) registerBuiltin("Promise", ofType: .jsPromiseConstructor) @@ -575,17 +732,20 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("WeakSet", ofType: .jsWeakSetConstructor) registerBuiltin("WeakRef", ofType: .jsWeakRefConstructor) registerBuiltin("FinalizationRegistry", ofType: .jsFinalizationRegistryConstructor) + registerBuiltin("DisposableStack", ofType: .jsDisposableStackConstructor) + registerBuiltin("AsyncDisposableStack", ofType: .jsAsyncDisposableStackConstructor) registerBuiltin("Math", ofType: .jsMathObject) + registerBuiltin("Atomics", ofType: .jsAtomicsObject) registerBuiltin("JSON", ofType: .jsJSONObject) registerBuiltin("Reflect", ofType: .jsReflectObject) registerBuiltin("isNaN", ofType: .jsIsNaNFunction) registerBuiltin("isFinite", ofType: .jsIsFiniteFunction) - //registerBuiltin("escape:", ofType: .jsEscapeFunction) - //registerBuiltin("unescape:", ofType: .jsUnescapeFunction) - //registerBuiltin("decodeURI:", ofType: .jsDecodeURIFunction) - //registerBuiltin("decodeURIComponent:", ofType: .jsDecodeURIComponentFunction) - //registerBuiltin("encodeURI:", ofType: .jsEncodeURIFunction) - //registerBuiltin("encodeURIComponent:", ofType: .jsEncodeURIComponentFunction) + registerBuiltin("escape", ofType: .jsEscapeFunction) + registerBuiltin("unescape", ofType: .jsUnescapeFunction) + registerBuiltin("decodeURI", ofType: .jsDecodeURIFunction) + registerBuiltin("decodeURIComponent", ofType: .jsDecodeURIComponentFunction) + registerBuiltin("encodeURI", ofType: .jsEncodeURIFunction) + registerBuiltin("encodeURIComponent", ofType: .jsEncodeURIComponentFunction) registerBuiltin("eval", ofType: .jsEvalFunction) registerBuiltin("parseInt", ofType: .jsParseIntFunction) registerBuiltin("parseFloat", ofType: .jsParseFloatFunction) @@ -620,24 +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())" + ) } 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 { @@ -670,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 @@ -731,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 } @@ -742,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) } } } @@ -753,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) } } } @@ -768,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) { @@ -781,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) { @@ -796,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 { @@ -812,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 { @@ -830,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") } @@ -845,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") } @@ -867,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 @@ -877,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 { @@ -905,6 +1098,18 @@ public class JavaScriptEnvironment: ComponentBase { $0 || type.Is($1) } } + + func isValidIdentifierOrIndex(_ name: String) -> Bool { + return (try? ValidationRegexes.identifierOrIndex.wholeMatch(in: name)) != nil + } + + func isValidDotNotationName(_ name: String) -> Bool { + return (try? ValidationRegexes.dotNotationName.wholeMatch(in: name)) != nil + } + + func isValidPropertyIndex(_ name: String) -> Bool { + return (try? ValidationRegexes.propertyIndex.wholeMatch(in: name)) != nil + } } /// A struct to encapsulate property and method type information for a group of related objects. @@ -912,6 +1117,7 @@ public struct ObjectGroup { public let name: String public var properties: [String: ILType] public var methods: [String: [Signature]] + // This may be used in custom profiles of Fuzzilli users' (e.g. ChromiumProfile.swift). public let parent: String? // Path to constructor function from `globalThis` if available (e.g. `["Temporal", "Instant"]`). public let constructorPath: [String]? @@ -919,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 @@ -930,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) } } @@ -965,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) || + 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: [:]) } } @@ -993,251 +1219,535 @@ 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"]) + 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"]) - - /// Type of a function's arguments object. - static let jsArguments = ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) + 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. + public static let jsArguments = + ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) + + /// Type of a JavaScript Iterator object. + 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. + 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"]) + 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"]) + 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"]) + 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. + public static let jsDisposableStack = ILType.object( + ofGroup: "DisposableStack", withProperties: ["disposed"], + withMethods: ["dispose", "use", "adopt", "defer", "move"]) + + /// Type of a JavaScript AsyncDisposableStack object. + 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", "transfer"]) + 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", "getFloat32", "getFloat64", "getBigInt64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat32", "setFloat64", "setBigInt64"]) + 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: ["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. + fileprivate static let someTypedArray = ILType.object() /// 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"]) + 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", "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)) + 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"]) + 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.jsFunction([.string] => .jsRegExp) + 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 { - return .functionAndConstructor([.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", + withProperties: ["name", "prototype", "stackTraceLimit"], + withMethods: ["isError", "captureStackTrace"]) } /// 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"], + withMethods: methods) } - static let jsUint8ArrayConstructor = jsTypedArrayConstructor("Uint8Array") - + .object(ofGroup: "Uint8ArrayConstructor", withProperties: ["prototype"], withMethods: ["fromBase64", "fromHex"]) - /// 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) + 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"]) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + public static let jsFinalizationRegistryConstructor = + ILType.constructor([.function()] => .jsFinalizationRegistry) + + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) + + /// Type of the JavaScript DisposableStack constructor builtin. + public static let jsDisposableStackConstructor = + ILType.constructor([] => .jsDisposableStack) + + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) + + /// Type of the JavaScript AsyncDisposableStack constructor builtin. + 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"], withMethods: ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "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. + 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", "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"]) + 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.`? @@ -1245,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. @@ -1297,22 +1912,38 @@ 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) -> 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)) }) - // These functions are getters instead of regular functions, and error when called - // on the prototype. We hide them from the prototype object to avoid - // generating `let v0 = Intl.DateTimeFormat.prototype.format`. - // https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.format - if receiver.name == "Intl.DateTimeFormat" || receiver.name == "Intl.NumberFormat" { - properties.removeValue(forKey: "format") - } else if receiver.name == "Intl.Collator" { - properties.removeValue(forKey: "compare") + var properties = Dictionary( + uniqueKeysWithValues: receiver.methods.map { + ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) + }) + + properties.merge(additionalProperties) { _, _ in + fatalError("duplicate property") + } + + // Each .prototype has a constructor property. + // In general, the following should hold true: + // .prototype.constructor === ; + properties["constructor"] = constructor + // Some properties of the instance type do not come from the prototype, e.g. Iterator.next + // which comes from the Iterator protocol. + // Other properties are get accessors instead of regular functions, and error when accessed + // on the prototype. We hide them from the prototype object to avoid generating patterns + // like `let v0 = Intl.DateTimeFormat.prototype.format`. + for property in excludeProperties { + properties.removeValue(forKey: property) } 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: [:] ) @@ -1323,150 +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] => .jsString, - "matchAll" : [.regexp] => .jsString, - "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())] => .jsString, - //"toLocaleLowerCase" : [.opt(.string...] => .jsString, - //"toLocaleUpperCase" : [.opt(.string...] => .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, + "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" : [] => .jsArray, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined, - "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" : [] => .object(), // returns an array iterator - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .undefined, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .undefined, - "values" : [] => .object(), - "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, ] ) + public static let jsFunctionPrototype = createPrototypeObjectGroup( + jsFunctions, + constructor: .jsFunctionConstructor) + + public static let jsFunctionConstructor = ObjectGroup( + name: "FunctionConstructor", + constructorPath: "Function", + instanceType: .jsFunctionConstructor, + properties: [ + "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: [ @@ -1476,606 +2137,994 @@ public extension ObjectGroup { methods: [:] ) - static let jsGenerators = ObjectGroup( + public static let jsIterator = ObjectGroup( + name: "Iterator", + instanceType: .jsIterator, + properties: [ + "done": .boolean, + "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, return and throw are part of the Iterator protocol, not Iterator.prototype. + public static let jsIteratorPrototype = createPrototypeObjectGroup( + jsIterator, + constructor: .jsIteratorConstructor, + excludeProperties: ["next", "return", "throw"]) + + public static let jsIteratorConstructor = ObjectGroup( + name: "IteratorConstructor", + instanceType: .jsIteratorConstructor, + properties: [ + "prototype": jsIteratorPrototype.instanceType + ], + methods: [ + "from": [.jsAnything] => .jsIterator, + "concat": [.jsAnything...] => .jsIterator, + "zip": [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] + => .jsIterator, + ] + ) + + 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" : [] => .object(), - "forEach" : [.function(), .opt(.object())] => .undefined, - "get" : [.jsAnything] => .jsAnything, - "has" : [.jsAnything] => .boolean, - "keys" : [] => .object(), - "set" : [.jsAnything, .jsAnything] => .jsMap, - "values" : [] => .object(), + "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, + ] + ) + + public static let jsProxyConstructor = ObjectGroup( + name: "ProxyConstructor", + constructorPath: "Proxy", + instanceType: .jsProxyConstructor, + properties: [:], + methods: [ + "revocable": [.object(), .object()] => .object(withProperties: ["proxy", "revoke"]) + ] + ) + + public static let jsMapPrototype = createPrototypeObjectGroup( + jsMaps, + constructor: .jsMapConstructor) + + public static let jsMapConstructor = ObjectGroup( + name: "MapConstructor", + constructorPath: "Map", + instanceType: .jsMapConstructor, + properties: [ + "prototype": jsMapPrototype.instanceType + ], + methods: [ + "groupBy": [.iterable, .function()] => .jsMap ] ) /// 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, + "delete": [.jsAnything] => .boolean, + "get": [.jsAnything] => .jsAnything, + "has": [.jsAnything] => .boolean, + "set": [.jsAnything, .jsAnything] => .jsWeakMap, + "getOrInsert": [.jsAnything, .jsAnything] => .jsAnything, + "getOrInsertComputed": [.jsAnything, .function()] => .jsAnything, ] ) + public static let jsWeakMapPrototype = createPrototypeObjectGroup( + jsWeakMaps, + constructor: .jsWeakMapConstructor) + + public static let jsWeakMapConstructor = ObjectGroup( + name: "WeakMapConstructor", + constructorPath: "WeakMap", + instanceType: .jsWeakMapConstructor, + properties: [ + "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, - "entries" : [] => .object(), - "forEach" : [.function(), .opt(.object())] => .undefined, - "has" : [.jsAnything] => .boolean, - "keys" : [] => .object(), - "values" : [] => .object(), + "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, ] ) + public static let jsSetPrototype = createPrototypeObjectGroup( + jsSets, + constructor: .jsSetConstructor) + + public static let jsSetConstructor = ObjectGroup( + name: "SetConstructor", + constructorPath: "Set", + instanceType: .jsSetConstructor, + properties: [ + "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, ] ) + public static let jsWeakSetPrototype = createPrototypeObjectGroup( + jsWeakSets, + constructor: .jsWeakSetConstructor) + + public static let jsWeakSetConstructor = ObjectGroup( + name: "WeakSetConstructor", + constructorPath: "WeakSet", + instanceType: .jsWeakSetConstructor, + properties: [ + "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() ] ) + public static let jsWeakRefPrototype = createPrototypeObjectGroup( + jsWeakRefs, + constructor: .jsWeakRefConstructor) + + public static let jsWeakRefConstructor = ObjectGroup( + name: "WeakRefConstructor", + constructorPath: "WeakRef", + instanceType: .jsWeakRefConstructor, + properties: [ + "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())] => .object(), - "unregister" : [.jsAnything] => .undefined, + "register": [.object(), .jsAnything, .opt(.object())] => .undefined, + "unregister": [.jsAnything] => .boolean, + ] + ) + + public static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup( + jsFinalizationRegistrys, + constructor: .jsFinalizationRegistryConstructor) + + public static let jsFinalizationRegistryConstructor = ObjectGroup( + name: "FinalizationRegistryConstructor", + constructorPath: "FinalizationRegistry", + instanceType: .jsFinalizationRegistryConstructor, + properties: [ + "prototype": jsFinalizationRegistryPrototype.instanceType + ], + methods: [:] + ) + + /// ObjectGroup modelling JavaScript DisposableStack objects + public static let jsDisposableStacks = ObjectGroup( + name: "DisposableStack", + instanceType: .jsDisposableStack, + properties: [ + "disposed": .boolean + ], + methods: [ + "dispose": [] => .undefined, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsDisposableStack, + ] + ) + + public static let jsDisposableStackPrototype = createPrototypeObjectGroup( + jsDisposableStacks, + constructor: .jsDisposableStackConstructor) + + public static let jsDisposableStackConstructor = ObjectGroup( + name: "DisposableStackConstructor", + constructorPath: "DisposableStack", + instanceType: .jsDisposableStackConstructor, + properties: [ + "prototype": jsDisposableStackPrototype.instanceType + ], + methods: [:] + ) + + /// ObjectGroup modelling JavaScript AsyncDisposableStack objects + public static let jsAsyncDisposableStacks = ObjectGroup( + name: "AsyncDisposableStack", + instanceType: .jsAsyncDisposableStack, + properties: [ + "disposed": .boolean + ], + methods: [ + "disposeAsync": [] => .jsPromise, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsAsyncDisposableStack, ] ) + public static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup( + jsAsyncDisposableStacks, + constructor: .jsAsyncDisposableStackConstructor) + + public static let jsAsyncDisposableStackConstructor = ObjectGroup( + name: "AsyncDisposableStackConstructor", + constructorPath: "AsyncDisposableStack", + instanceType: .jsAsyncDisposableStackConstructor, + properties: [ + "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" : [.integer, .opt(.integer)] => .jsArrayBuffer, - "transfer" : [] => .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: [ - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer, - "length" : .integer + "BYTES_PER_ELEMENT": .integer, + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, + "length": .integer, ], methods: [ - "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .undefined, - "entries" : [] => .jsArray, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined, - "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" : [] => .object(), // returns an array iterator - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .undefined, - "set" : [.object(), .opt(.integer)] => .undefined, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .undefined, - "values" : [] => .object(), - "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 let jsUint8ArrayPrototype = createPrototypeObjectGroup(jsTypedArrays("Uint8Array")) + public static func jsTypedArrayPrototype(_ variant: String) -> ObjectGroup { + return createPrototypeObjectGroup( + jsTypedArrays(variant), + constructor: .jsTypedArrayConstructor(variant), + additionalProperties: [ + "BYTES_PER_ELEMENT": .integer + ]) + } - static let jsUint8ArrayConstructor = ObjectGroup( - name: "Uint8ArrayConstructor", - instanceType: .jsUint8ArrayConstructor, + public static func jsTypedArrayConstructor(_ variant: String) -> ObjectGroup { + let methods: [String: Signature] = + variant == "Uint8Array" + ? [ + "fromBase64": [ + .plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType), + ] => .jsUint8Array, + "fromHex": [.plain(.string)] => .jsUint8Array, + ] + : [:] + return ObjectGroup( + name: "\(variant)Constructor", + constructorPath: variant, + instanceType: .jsTypedArrayConstructor(variant), + properties: [ + "prototype": jsTypedArrayPrototype(variant).instanceType, + "BYTES_PER_ELEMENT": .integer, + ], + methods: methods + ) + } + + /// ObjectGroup modelling JavaScript DataView objects + public static let jsDataViews = ObjectGroup( + name: "DataView", + instanceType: .jsDataView, properties: [ - "prototype": jsUint8ArrayPrototype.instanceType, + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, ], methods: [ - "fromBase64": [.plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType)] => .jsUint8Array, - "fromHex": [.plain(.string)] => .jsUint8Array, + "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, ] ) - /// ObjectGroup modelling JavaScript DataView objects - static let jsDataViews = ObjectGroup( - name: "DataView", - instanceType: .jsDataView, + public static let jsDataViewPrototype = createPrototypeObjectGroup( + jsDataViews, + constructor: .jsDataViewConstructor) + + public static let jsDataViewConstructor = ObjectGroup( + name: "DataViewConstructor", + constructorPath: "DataView", + instanceType: .jsDataViewConstructor, properties: [ - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer + "prototype": jsDataViewPrototype.instanceType ], - methods: [ - "getInt8" : [.integer] => .integer, - "getUint8" : [.integer] => .integer, - "getInt16" : [.integer] => .integer, - "getUint16" : [.integer] => .integer, - "getInt32" : [.integer] => .integer, - "getUint32" : [.integer] => .integer, - "getFloat32" : [.integer] => .float, - "getFloat64" : [.integer] => .float, - "getBigInt64": [.integer] => .bigint, - "setInt8" : [.integer, .integer] => .undefined, - "setUint8" : [.integer, .integer] => .undefined, - "setInt16" : [.integer, .integer] => .undefined, - "setUint16" : [.integer, .integer] => .undefined, - "setInt32" : [.integer, .integer] => .undefined, - "setUint32" : [.integer, .integer] => .undefined, - "setFloat32" : [.integer, .float] => .undefined, - "setFloat64" : [.integer, .float] => .undefined, - "setBigInt64": [.integer, .bigint] => .undefined, - ] - ) - - static let jsPromisePrototype = createPrototypeObjectGroup(jsPromises) + methods: [:] + ) + + 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" : [.jsPromise...] => .jsPromise, - "any" : [.jsPromise...] => .jsPromise, - "race" : [.jsPromise...] => .jsPromise, - "allSettled" : [.jsPromise...] => .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" : [] => .jsString, - //"toLocaleDateString" : [.localeObject] => .jsString, - //"toLocaleTimeString" : [.localeObject] => .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] => .jsDate, - "setMilliseconds" : [.number] => .jsDate, - "setUTCMilliseconds" : [.number] => .jsDate, - "setSeconds" : [.number] => .jsDate, - "setUTCSeconds" : [.number, .opt(.number)] => .jsDate, - "setMinutes" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setUTCMinutes" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setHours" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setUTCHours" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setDate" : [.number] => .jsDate, - "setUTCDate" : [.number] => .jsDate, - "setMonth" : [.number] => .jsDate, - "setUTCMonth" : [.number] => .jsDate, - "setFullYear" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setUTCFullYear" : [.number, .opt(.number), .opt(.number)] => .jsDate, - "setYear" : [.number] => .jsDate, - "toJSON" : [] => .jsString, - "toUTCString" : [] => .jsString, - "toGMTString" : [] => .jsString, - "toTemporalInstant" : [] => .jsTemporalInstant, - ] - ) - - static let jsDatePrototype = createPrototypeObjectGroup(jsDate) + "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, + ] + ) + + 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)] => .jsDate, - "now" : [] => .jsDate, - "parse" : [.string] => .jsDate, + "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()] => .undefined, - "create" : [.object(), .object()] => .object(), - "defineProperty" : [.object(), .string, .oneof(.object(withProperties: ["configurable", "writable", "enumerable", "value"]), .object(withMethods: ["get", "set"]))] => .undefined, - "defineProperties" : [.object(), .object()] => .undefined, - "entries" : [.object()] => .object(), - "freeze" : [.object()] => .undefined, - "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, + "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, - "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 = createPrototypeObjectGroup(jsArrayBuffers) + 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) + 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 = createPrototypeObjectGroup(jsStrings) + 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, + ] + ) + + public static let jsRegExpPrototype = createPrototypeObjectGroup( + jsRegExps, constructor: .jsRegExpConstructor) + + /// Object group modelling the JavaScript RegExp constructor builtin + public static let jsRegExpConstructor = ObjectGroup( + name: "RegExpConstructor", + constructorPath: "RegExp", + instanceType: .jsRegExpConstructor, + properties: [ + "prototype": jsRegExpPrototype.instanceType, + "$1": .jsString, + "$2": .jsString, + "$3": .jsString, + "$4": .jsString, + "$5": .jsString, + "$6": .jsString, + "$7": .jsString, + "$8": .jsString, + "$9": .jsString, + "$_": .jsString, + "input": .jsString, + "lastMatch": .jsString, + "lastParen": .jsString, + "leftContext": .jsString, + ], + methods: [ + "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, + "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 + "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, - "hypot" : [.jsAnything...] => .number, - "imul" : [.jsAnything, .jsAnything] => .integer, - "log" : [.jsAnything] => .number, - "log1p" : [.jsAnything] => .number, - "log10" : [.jsAnything] => .number, - "log2" : [.jsAnything] => .number, - "max" : [.jsAnything...] => .jsAnything, - "min" : [.jsAnything...] => .jsAnything, - "pow" : [.jsAnything, .jsAnything] => .number, - "random" : [] => .number, - "round" : [.jsAnything] => .number, - "sign" : [.jsAnything] => .number, - "sin" : [.jsAnything] => .number, - "sinh" : [.jsAnything] => .number, - "sqrt" : [.jsAnything] => .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, + ] + ) + + /// Object group modelling the JavaScript Atomics builtin + /// 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. + 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, ] ) /// 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, + "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" : [.jsAnything] => .jsAnything, - "has" : [.object(), .string] => .boolean, - "isExtensible" : [.jsAnything] => .boolean, - "ownKeys" : [.jsAnything] => .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 + ] + ) + } + + public static func jsErrorPrototype(_ variant: String) -> ObjectGroup { + return createPrototypeObjectGroup( + jsError(variant), + constructor: .jsErrorConstructor(variant), + additionalProperties: [ + "message": .jsString, + "name": .jsString, + ]) + } + + public static func jsErrorConstructor(_ variant: String) -> ObjectGroup { + return ObjectGroup( + name: "\(variant)Constructor", + constructorPath: variant, + instanceType: .jsErrorConstructor(variant), + properties: [ + "name": .jsString, + "prototype": jsErrorPrototype(variant).instanceType, + "stackTraceLimit": .integer, ], methods: [ - "toString" : [] => .jsString, + "isError": [.jsAnything] => .boolean, + "captureStackTrace": [.object(), .opt(.function())] => .undefined, ] ) } // 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: [ @@ -2087,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, @@ -2106,84 +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 = createPrototypeObjectGroup(jsWasmGlobal) + 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 = createPrototypeObjectGroup(jsWasmMemory) + 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 = createPrototypeObjectGroup(wasmTable) + 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 = createPrototypeObjectGroup(jsWasmTag) + 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, @@ -2191,30 +3246,65 @@ public extension ObjectGroup { ] ) - static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup(jsWebAssemblyException) + 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: [:] ) // WebAssembly.CompileError, .LinkError, .RuntimeError don't offer anything interesting but a // constructor. + fileprivate static let jsWebAssemblyError = ObjectGroup( + name: "WebAssemblyError", + instanceType: nil, + properties: [ + "message": .jsString, + "name": .jsString, + ], + methods: [:] + ) + fileprivate static let webAssemblyErrorConstructorType = - ILType.constructor([.opt(.string), .opt(.object() | .string), .opt(.string)] => .object()) - + .object(withProperties: ["prototype"]) - fileprivate static let webAssemblySuspendingConstructorType = ILType.constructor([.plain(.function())] => .object()) + ILType.constructor( + [.opt(.string), .opt(.object() | .string), .opt(.string)] + => jsWebAssemblyError.instanceType) + + .object(ofGroup: "WebAssemblyErrorConstructor", withProperties: ["prototype"]) + + fileprivate static let jsWebAssemblyErrorPrototype = createPrototypeObjectGroup( + jsWebAssemblyError, + constructor: webAssemblyErrorConstructorType, + additionalProperties: [ + "message": .jsString, + "name": .jsString, + ] + ) + + fileprivate static let jsWebAssemblyErrorConstructor = ObjectGroup( + name: "WebAssemblyErrorConstructor", + instanceType: webAssemblyErrorConstructorType, + properties: [ + "prototype": jsWebAssemblyErrorPrototype.instanceType + ], + methods: [:] + ) + + 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, @@ -2230,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: [ @@ -2298,7 +3399,7 @@ public extension ObjectGroup { ] ) - static let jsWasmSuspendingObject = ObjectGroup( + public static let jsWasmSuspendingObject = ObjectGroup( name: "WasmSuspendingObject", instanceType: .object(ofGroup: "WasmSuspendingObject"), properties: [:], @@ -2308,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 { @@ -2341,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), @@ -2349,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: [ @@ -2390,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], @@ -2398,29 +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 = createPrototypeObjectGroup(jsTemporalInstant) + 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: [ @@ -2442,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], @@ -2451,23 +3576,27 @@ public extension ObjectGroup { ] ) - static let jsTemporalDurationPrototype = createPrototypeObjectGroup(jsTemporalDuration) + 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: [ @@ -2479,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], @@ -2492,18 +3628,21 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainTimePrototype = createPrototypeObjectGroup(jsTemporalPlainTime) + 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), ] ) @@ -2519,43 +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(jsTemporalPlainYearMonth) + 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: [ @@ -2564,143 +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(jsTemporalPlainMonthDay) + 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(jsTemporalPlainDate) + 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(jsTemporalPlainDateTime) + 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], @@ -2708,19 +3932,25 @@ public extension ObjectGroup { ] ) - static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup(jsTemporalZonedDateTime) + 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), ] ) @@ -2747,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( @@ -2791,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, @@ -2819,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 @@ -2859,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 @@ -2897,7 +4178,7 @@ extension OptionsBag { static let jsTemporalOverflowSettings = OptionsBag( name: "jsTemporalOverflowSettingsObject", properties: [ - "overflow": jsTemporalOverflowEnum, + "overflow": jsTemporalOverflowEnum ]) static let jsTemporalZonedInterpretationSettings = OptionsBag( @@ -2908,7 +4189,7 @@ extension OptionsBag { "offset": jsTemporalOffsetEnum, ]) - static let jsTemporalDurationRoundToSettings = OptionsBag( + static let jsTemporalDurationRoundToSettings = OptionsBag( name: "TemporalDurationRoundToSettingsObject", properties: [ "largestUnit": OptionsBag.jsTemporalUnitEnum, @@ -2918,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 ] ) @@ -2944,49 +4225,173 @@ extension OptionsBag { // Intl extension ILType { // Intl types - static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "ListFormat", "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter"], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) - - 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 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 jsIntlLocaleLike = ILType.namedString(ofName: "IntlLocaleString") - static let jsIntlUnit = ILType.namedString(ofName: "IntlUnitString") + 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") + static let jsIntlScriptString = ILType.namedString(ofName: "IntlScriptString") + static let jsIntlRegionString = ILType.namedString(ofName: "IntlRegionString") + static let jsIntlVariantString = ILType.namedString(ofName: "IntlVariantString") + // TODO: locale-likes are actually supposed to be a locale string, an Intl.Locale object, or an array of the same + static let jsIntlLocaleLike = ILType.jsIntlLocaleString + static let jsIntlUnitString = ILType.namedString(ofName: "IntlUnitString") } 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, - "ListFormat" : .jsIntlListFormatConstructor, - "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, @@ -3004,25 +4409,104 @@ extension ObjectGroup { ] ) - static let jsIntlCollatorPrototype = createPrototypeObjectGroup(jsIntlCollator) + // Exclude compare as it is a get accessor, not a property, meaning that + // Intl.Collator.prototype.compare throws unconditionally (even without calling it). + static let jsIntlCollatorPrototype = createPrototypeObjectGroup( + jsIntlCollator, + constructor: .jsIntlCollatorConstructor, + excludeProperties: ["compare"]) static let jsIntlCollatorConstructor = ObjectGroup( name: "IntlCollatorConstructor", 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 + ] + ) + + static let jsIntlDisplayNames = ObjectGroup( + name: "Intl.DisplayNames", + instanceType: .jsIntlDisplayNames, + properties: [:], + methods: [ + "of": [.string] => .string, // TODO(mliedtke): The parameter should be typed more precise than string. + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "style", "type", "fallback", "languageDisplay", + ]), + ] + ) + + static let jsIntlDisplayNamesPrototype = createPrototypeObjectGroup( + jsIntlDisplayNames, + constructor: .jsIntlDisplayNamesConstructor) + + static let jsIntlDisplayNamesConstructor = ObjectGroup( + name: "IntlDisplayNamesConstructor", + constructorPath: "Intl.DisplayNames", + instanceType: .jsIntlDisplayNamesConstructor, + properties: [ + "prototype": jsIntlDisplayNamesPrototype.instanceType + ], + methods: [ + // TODO(manishearth) this also accepts arrays of locale-likes + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray + ] + ) + + static let jsIntlDurationFormat = ObjectGroup( + name: "Intl.DurationFormat", + instanceType: .jsIntlDurationFormat, + properties: [:], + methods: [ + "format": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] => .string, + "formatToParts": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] + => .jsArray, + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "numberingSystem", "style", "fractionalDigits", + ]), + ] + ) + + static let jsIntlDurationFormatPrototype = createPrototypeObjectGroup( + jsIntlDurationFormat, + constructor: .jsIntlDurationFormatConstructor) + + static let jsIntlDurationFormatConstructor = ObjectGroup( + name: "IntlDurationFormatConstructor", + constructorPath: "Intl.DurationFormat", + instanceType: .jsIntlDurationFormatConstructor, + properties: [ + "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 } } @@ -3048,18 +4532,26 @@ extension ObjectGroup { ] ) - static let jsIntlDateTimeFormatPrototype = createPrototypeObjectGroup(jsIntlDateTimeFormat) + // Exclude format as it is a get accessor, not a property, meaning that + // Intl.DateTimeFormat.prototype.format throws unconditionally (even without calling it). + static let jsIntlDateTimeFormatPrototype = createPrototypeObjectGroup( + jsIntlDateTimeFormat, + constructor: .jsIntlDateTimeFormatConstructor, + excludeProperties: ["format"]) static let jsIntlDateTimeFormatConstructor = ObjectGroup( name: "IntlDateTimeFormatConstructor", 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 ] ) @@ -3074,21 +4566,69 @@ extension ObjectGroup { ] ) - static let jsIntlListFormatPrototype = createPrototypeObjectGroup(jsIntlListFormat) + static let jsIntlListFormatPrototype = createPrototypeObjectGroup( + jsIntlListFormat, + constructor: .jsIntlListFormatConstructor) static let jsIntlListFormatConstructor = ObjectGroup( name: "IntlListFormatConstructor", 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 + ] + ) + + static let jsIntlLocale = ObjectGroup( + name: "Intl.Locale", + instanceType: .jsIntlLocale, + properties: [ + "baseName": .string, + "calendar": .string, + "caseFirst": .string, + "collation": .string, + "hourCycle": .string, + "language": .string, + "numberingSystem": .string, + "numeric": .string, + "region": .string, + "script": .string, + "variants": .string, + ], + methods: [ + "getCalendars": [] => .jsArray, + "getCollations": [] => .jsArray, + "getHourCycles": [] => .jsArray, + "getNumberingSystems": [] => .jsArray, + "getTextInfo": [] => .jsArray, + "getTimeZones": [] => .jsArray, + "getWeekInfo": [] => .object(), + "maximize": [] => .jsIntlLocale, + "minimize": [] => .jsIntlLocale, + "toString": [] => .string, ] ) + static let jsIntlLocalePrototype = + createPrototypeObjectGroup(jsIntlLocale, constructor: .jsIntlLocaleConstructor) + + static let jsIntlLocaleConstructor = ObjectGroup( + name: "IntlLocaleConstructor", + constructorPath: "Intl.Locale", + instanceType: .jsIntlLocaleConstructor, + properties: [ + "prototype": jsIntlLocalePrototype.instanceType + ], + methods: [:] + ) + fileprivate static func numberFormatSignature(_ returnType: ILType) -> [Signature] { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/format [ILType.number, .bigint, .string].map { @@ -3116,18 +4656,26 @@ extension ObjectGroup { ] ) - static let jsIntlNumberFormatPrototype = createPrototypeObjectGroup(jsIntlNumberFormat) + // Exclude format as it is a get accessor, not a property, meaning that + // Intl.NumberFormat.prototype.format throws unconditionally (even without calling it). + static let jsIntlNumberFormatPrototype = createPrototypeObjectGroup( + jsIntlNumberFormat, + constructor: .jsIntlNumberFormatConstructor, + excludeProperties: ["format"]) static let jsIntlNumberFormatConstructor = ObjectGroup( name: "IntlNumberFormatConstructor", 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 ] ) @@ -3142,22 +4690,28 @@ extension ObjectGroup { ] ) - static let jsIntlPluralRulesPrototype = createPrototypeObjectGroup(jsIntlPluralRules) + static let jsIntlPluralRulesPrototype = + createPrototypeObjectGroup(jsIntlPluralRules, constructor: .jsIntlPluralRulesConstructor) static let jsIntlPluralRulesConstructor = ObjectGroup( name: "IntlPluralRulesConstructor", 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", @@ -3170,18 +4724,23 @@ extension ObjectGroup { ] ) - static let jsIntlRelativeTimeFormatPrototype = createPrototypeObjectGroup(jsIntlRelativeTimeFormat) + static let jsIntlRelativeTimeFormatPrototype = createPrototypeObjectGroup( + jsIntlRelativeTimeFormat, + constructor: .jsIntlRelativeTimeFormatConstructor) static let jsIntlRelativeTimeFormatConstructor = ObjectGroup( name: "IntlRelativeTimeFormatConstructor", 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 ] ) @@ -3195,18 +4754,22 @@ extension ObjectGroup { ] ) - static let jsIntlSegmenterPrototype = createPrototypeObjectGroup(jsIntlSegmenter) + static let jsIntlSegmenterPrototype = + createPrototypeObjectGroup(jsIntlSegmenter, constructor: .jsIntlSegmenterConstructor) static let jsIntlSegmenterConstructor = ObjectGroup( name: "IntlSegmenterConstructor", 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( @@ -3214,44 +4777,95 @@ 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 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 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( - name: "IntlLocaleSettings", + name: "IntlDateTimeFormatSettings", properties: [ // Locale options "localeMatcher": jsIntlLocaleMatcherEnum, @@ -3270,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 @@ -3293,6 +4907,49 @@ extension OptionsBag { ] ) + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/DisplayNames#options + static let jsIntlDisplayNamesSettings = OptionsBag( + name: "IntlDisplayNamesSettings", + properties: [ + "localeMatcher": jsIntlLocaleMatcherEnum, + "style": jsIntlLongShortNarrowEnum, + "type": jsIntlDisplayNamesTypeEnum, + "fallback": jsIntlDisplayNamesFallbackEnum, + "languageDisplay": jsIntlDisplayNamesLanguageDisplayEnum, + ] + ) + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DurationFormat/DurationFormat#options + static let jsIntlDurationFormatSettings = OptionsBag( + name: "IntlDurationFormatSettings", + properties: [ + "localeMatcher": jsIntlLocaleMatcherEnum, + "numberingSystem": jsIntlNumberingSystemEnum, + "style": jsIntlDurationFormatStyleEnum, + "years": jsIntlLongShortNarrowEnum, + "yearsDisplay": jsIntlAutoAlwaysEnum, + "months": jsIntlLongShortNarrowEnum, + "monthsDisplay": jsIntlAutoAlwaysEnum, + "weeks": jsIntlLongShortNarrowEnum, + "weeksDisplay": jsIntlAutoAlwaysEnum, + "days": jsIntlLongShortNarrowEnum, + "daysDisplay": jsIntlAutoAlwaysEnum, + "hours": jsIntlLongShortNarrowEnum, + "hoursDisplay": jsIntlAutoAlwaysEnum, + "minutes": jsIntlLongShortNarrowEnum, + "minutesDisplay": jsIntlAutoAlwaysEnum, + "seconds": jsIntlLongShortNarrowEnum, + "secondsDisplay": jsIntlAutoAlwaysEnum, + "milliseconds": jsIntlLongShortNarrowEnum, + "millisecondsDisplay": jsIntlAutoAlwaysEnum, + "microseconds": jsIntlLongShortNarrowEnum, + "microsecondsDisplay": jsIntlAutoAlwaysEnum, + "nanoseconds": jsIntlLongShortNarrowEnum, + "nanosecondsDisplay": jsIntlAutoAlwaysEnum, + "fractionalDigits": .integer, + ] + ) + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#options static let jsIntlListFormatSettings = OptionsBag( name: "IntlListFormatSettings", @@ -3303,6 +4960,23 @@ extension OptionsBag { ] ) + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/Locale#options + static let jsIntlLocaleSettings = OptionsBag( + name: "IntlLocaleSettings", + properties: [ + "language": .jsIntlLanguageString, + "script": .jsIntlScriptString, + "region": .jsIntlRegionString, + "variants": .jsIntlVariantString, + "calendar": .jsTemporalCalendarEnum, + "collation": jsIntlCollationTypeEnum, + "numberingSystem": jsIntlNumberingSystemEnum, + "caseFirst": jsIntlCaseFirstEnum, + "hourCycle": jsIntlHourCycleEnum, + "numeric": .boolean, + ] + ) + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options static let jsIntlNumberFormatSettings = OptionsBag( name: "IntlNumberFormatSettings", @@ -3315,7 +4989,7 @@ extension OptionsBag { "currency": jsIntlCurrencySystemEnum, "currencyDisplay": jsIntlCurrencyDisplayEnum, "currencySign": jsIntlCurrencySignEnum, - "unit": .jsIntlUnit, + "unit": .jsIntlUnitString, "unitDisplay": jsIntlLongShortNarrowEnum, // digit options "minimumIntegerDigits": .integer, @@ -3378,7 +5052,21 @@ 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"]) + + static let jsIteratorZipSettings = OptionsBag( + name: "IteratorZipSettings", + properties: [ + "mode": jsIteratorZipModeEnum, + "padding": .iterable, ] ) } @@ -3388,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", @@ -3401,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 c365ff1ef..447db8043 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 { @@ -149,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") } @@ -192,8 +193,8 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { return false } - if execution.outcome.isCrash() { - // For crashes, we don't care about the edges that were triggered, just about the outcome itself. + if execution.outcome.isCrash() || execution.outcome.isDifferential() { + // For crashes and differentials, we don't care about the edges that were triggered, just about the outcome itself. return true } @@ -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 5d23c70a2..09a32b7c0 100644 --- a/Sources/Fuzzilli/Execution/Execution.swift +++ b/Sources/Fuzzilli/Execution/Execution.swift @@ -20,6 +20,12 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { case failed(Int) case succeeded case timedOut + // This outcome is added to support native differential fuzzing. + // It should get very similar treatment to crashed -> if the run resulted + // in a differential, most likely there's a bug. + // Please note that this feature is unstable yet, so the statement above + // might not always be the case. + case differential public var description: String { switch self { @@ -31,6 +37,8 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { return "Succeeded" case .timedOut: return "TimedOut" + case .differential: + return "Differential" } } @@ -49,6 +57,14 @@ public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable { return false } } + + public func isDifferential() -> Bool { + if case .differential = self { + return true + } else { + return false + } + } } /// The result of executing a program. @@ -59,3 +75,59 @@ public protocol Execution { var fuzzout: String { get } var execTime: TimeInterval { get } } + +/// Struct to capture result of exection in differential mode +struct DiffExecution: Execution { + let outcome: ExecutionOutcome + let execTime: TimeInterval + let stdout: String + let stderr: String + let fuzzout: String + + private init( + outcome: ExecutionOutcome, + execTime: TimeInterval, + stdout: String, + stderr: String, + fuzzout: String + ) { + self.outcome = outcome + self.execTime = execTime + self.stdout = stdout + self.stderr = stderr + self.fuzzout = fuzzout + } + + // 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 { + + assert(optExec.outcome == .succeeded && unoptExec.outcome == .succeeded) + + func formatDiff(label: String, optData: String, unoptData: String) -> String { + return """ + === OPT \(label) === + \(optData) + + === UNOPT \(label) === + \(unoptData) + """ + } + + let relateOutcome = DiffOracle.relate(optDumpOut, with: unoptDumpOut) + + 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) + ) + } +} diff --git a/Sources/Fuzzilli/Execution/REPRL.swift b/Sources/Fuzzilli/Execution/REPRL.swift index 005310ec8..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,25 +112,42 @@ 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 { - logger.warning("Script execution failed: \(String(cString: reprl_get_last_error(reprlContext))). Retrying in 1 second...") + 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 { - logger.error("Script execution failed again: \(String(cString: reprl_get_last_error(reprlContext))). Giving up") + 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 childOutput = """ + stderr: + \(stderr.isEmpty ? "" : stderr) + stdout: + \(stdout.isEmpty ? "" : stdout) + """ + logger.error("Script execution failed again: \(errorMsg). Giving up\n\(childOutput)") // If we weren't able to successfully execute a script in the last N attempts, abort now... recentlyFailedExecutions += 1 if recentlyFailedExecutions >= 10 { diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index 2274e044f..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) } @@ -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 @@ -62,7 +64,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] @@ -95,9 +97,9 @@ struct DefUseAnalyzer: Analyzer { return uses[variable]!.map({ code[$0] }) } - /// Returns the indices of the instructions using the given variable. + /// Returns the indices of the instructions assigning to the given variable. func assignmentIndices(of variable: Variable) -> [Int] { - assert(uses.contains(variable)) + assert(assignments.contains(variable)) return assignments[variable]! } @@ -107,7 +109,7 @@ struct DefUseAnalyzer: Analyzer { return uses[variable]! } - /// Returns the number of instructions using the given variable. + /// Returns the number of instructions assigning to the given variable. func numAssignments(of variable: Variable) -> Int { assert(assignments.contains(variable)) return assignments[variable]!.count @@ -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() @@ -184,16 +191,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..1118a7073 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) } @@ -59,7 +65,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 +101,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() } @@ -140,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 @@ -151,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) } @@ -182,7 +190,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) } @@ -201,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 { @@ -219,7 +229,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 +238,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 +248,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 +268,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") } } @@ -306,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) @@ -485,6 +515,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..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 @@ -39,41 +40,43 @@ 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) + // Inside a bundle containing multiple scripts / modules + public static let bundle = Context(rawValue: 1 << 14) + + public static let empty = Context([]) - public static let empty = Context([]) - public var inWasm: Bool { self.contains(.wasm) || self.contains(.wasmFunction) } @@ -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 ee017f20a..ab49ed0ae 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 = .empty + ) where Variables.Element == Variable { assert(op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count) self.op = op self.inouts_ = Array(inouts) @@ -262,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. @@ -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)!)! } @@ -327,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) } } @@ -338,7 +341,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 +384,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 heapType): - let kind = switch 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 +511,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 @@ -543,14 +561,19 @@ 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): $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 +593,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,17 +622,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() + case .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() + case .endObjectLiteralComputedSetter: + $0.endObjectLiteralComputedSetter = + Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() case .endObjectLiteral: $0.endObjectLiteral = Fuzzilli_Protobuf_EndObjectLiteral() case .beginClassDefinition(let op): @@ -610,103 +661,87 @@ 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 .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) - } - 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 { + $0.isStatic = op.isStatic + } + 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 - $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .beginClassPrivateInstanceMethod(let op): - $0.beginClassPrivateInstanceMethod = Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) + case .endClassSetter: + $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() + case .beginClassComputedSetter(let op): + $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { + $0.isStatic = op.isStatic } - case .endClassPrivateInstanceMethod: - $0.endClassPrivateInstanceMethod = Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - case .classAddPrivateStaticProperty(let op): - $0.classAddPrivateStaticProperty = Fuzzilli_Protobuf_ClassAddPrivateStaticProperty.with { + case .endClassComputedSetter: + $0.endClassComputedSetter = Fuzzilli_Protobuf_EndClassComputedSetter() + 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: @@ -714,11 +749,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 @@ -773,13 +814,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) @@ -826,7 +873,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 { @@ -835,7 +882,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 @@ -860,7 +908,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 @@ -885,22 +935,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): @@ -924,20 +983,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 @@ -946,22 +1010,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(_): @@ -1006,7 +1082,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: @@ -1116,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 @@ -1127,23 +1209,29 @@ extension Instruction: ProtobufConvertible { $0.constf64 = Fuzzilli_Protobuf_Constf64.with { $0.value = op.value } case .constf32(let op): $0.constf32 = Fuzzilli_Protobuf_Constf32.with { $0.value = op.value } - case .wasmReturn(let op): - $0.wasmReturn = Fuzzilli_Protobuf_WasmReturn.with { - $0.returnTypes = op.returnTypes.map(ILTypeToWasmTypeEnum) - } + case .wasmReturn(_): + $0.wasmReturn = Fuzzilli_Protobuf_WasmReturn() case .wasmJsCall(let op): $0.wasmJsCall = Fuzzilli_Protobuf_WasmJsCall.with { - $0.parameterTypes = op.functionSignature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.functionSignature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) + $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) @@ -1186,25 +1274,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(_): @@ -1226,16 +1332,24 @@ 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(let op): - $0.wasmReassign = Fuzzilli_Protobuf_WasmReassign.with { $0.variableType = ILTypeToWasmTypeEnum(op.variableType) } + case .wasmReassign(_): + $0.wasmReassign = Fuzzilli_Protobuf_WasmReassign() case .wasmDefineGlobal(let op): $0.wasmDefineGlobal = Fuzzilli_Protobuf_WasmDefineGlobal.with { $0.wasmGlobal.isMutable = op.isMutable @@ -1290,24 +1404,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) @@ -1315,13 +1415,12 @@ extension Instruction: ProtobufConvertible { } case .wasmCallDirect(let op): $0.wasmCallDirect = Fuzzilli_Protobuf_WasmCallDirect.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) + $0.outputCount = Int32(op.numOutputs) } case .wasmReturnCallDirect(let op): $0.wasmReturnCallDirect = Fuzzilli_Protobuf_WasmReturnCallDirect.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) } case .wasmReturnCallIndirect(let op): $0.wasmReturnCallIndirect = Fuzzilli_Protobuf_WasmReturnCallIndirect.with { @@ -1330,12 +1429,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): @@ -1376,110 +1475,94 @@ 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 { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) } case .wasmEndBlock(let op): $0.wasmEndBlock = Fuzzilli_Protobuf_WasmEndBlock.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.numOutputs) } case .wasmBeginLoop(let op): $0.wasmBeginLoop = Fuzzilli_Protobuf_WasmBeginLoop.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) } case .wasmEndLoop(let op): $0.wasmEndLoop = Fuzzilli_Protobuf_WasmEndLoop.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.numOutputs) } case .wasmBeginTryTable(let op): $0.wasmBeginTryTable = Fuzzilli_Protobuf_WasmBeginTryTable.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) $0.catches = op.catches.map(convertWasmCatch) } case .wasmEndTryTable(let op): $0.wasmEndTryTable = Fuzzilli_Protobuf_WasmEndTryTable.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.numOutputs) } case .wasmBeginTry(let op): $0.wasmBeginTry = Fuzzilli_Protobuf_WasmBeginTry.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.numInputs - 1) } case .wasmBeginCatchAll(let op): $0.wasmBeginCatchAll = Fuzzilli_Protobuf_WasmBeginCatchAll.with { - $0.inputTypes = op.inputTypes.map(ILTypeToWasmTypeEnum) + $0.blockOutputCount = Int32(op.numInputs - 1) } case .wasmBeginCatch(let op): $0.wasmBeginCatch = Fuzzilli_Protobuf_WasmBeginCatch.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.blockOutputCount = Int32(op.blockOutputCount) + $0.labelParameterCount = Int32(op.labelParameterCount) } case .wasmEndTry(let op): $0.wasmEndTry = Fuzzilli_Protobuf_WasmEndTry.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) + $0.blockOutputCount = Int32(op.numOutputs) } case .wasmBeginTryDelegate(let op): $0.wasmBeginTryDelegate = Fuzzilli_Protobuf_WasmBeginTryDelegate.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.numInputs - 1) } case .wasmEndTryDelegate(let op): $0.wasmEndTryDelegate = Fuzzilli_Protobuf_WasmEndTryDelegate.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) - } - case .wasmThrow(let op): - $0.wasmThrow = Fuzzilli_Protobuf_WasmThrow.with { - $0.parameterTypes = op.parameterTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.numOutputs) } + case .wasmThrow(_): + $0.wasmThrow = Fuzzilli_Protobuf_WasmThrow() case .wasmThrowRef(_): $0.wasmThrowRef = Fuzzilli_Protobuf_WasmThrowRef() case .wasmRethrow(_): $0.wasmRethrow = Fuzzilli_Protobuf_WasmRethrow() - case .wasmDefineTag(let op): - $0.wasmDefineTag = Fuzzilli_Protobuf_WasmDefineTag.with { - $0.parameterTypes = op.parameterTypes.map(ILTypeToWasmTypeEnum) - } - case .wasmBranch(let op): - $0.wasmBranch = Fuzzilli_Protobuf_WasmBranch.with { - $0.parameters = op.labelTypes.map(ILTypeToWasmTypeEnum) - } + case .wasmDefineTag(_): + $0.wasmDefineTag = Fuzzilli_Protobuf_WasmDefineTag() + case .wasmBranch(_): + $0.wasmBranch = Fuzzilli_Protobuf_WasmBranch() case .wasmBranchIf(let op): $0.wasmBranchIf = Fuzzilli_Protobuf_WasmBranchIf.with { - $0.parameters = op.labelTypes.map(ILTypeToWasmTypeEnum) $0.hint = convertEnum(op.hint, WasmBranchHint.allCases) } case .wasmBranchTable(let op): $0.wasmBranchTable = Fuzzilli_Protobuf_WasmBranchTable.with { - $0.parameters = op.labelTypes.map(ILTypeToWasmTypeEnum) $0.valueCount = UInt32(op.valueCount) } case .wasmBeginIf(let op): $0.wasmBeginIf = Fuzzilli_Protobuf_WasmBeginIf.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) $0.inverted = op.inverted $0.hint = convertEnum(op.hint, WasmBranchHint.allCases) } case .wasmBeginElse(let op): $0.wasmBeginElse = Fuzzilli_Protobuf_WasmBeginElse.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) + $0.outputCount = Int32(op.outputCount) } case .wasmEndIf(let op): $0.wasmEndIf = Fuzzilli_Protobuf_WasmEndIf.with { - $0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.outputCount) } case .wasmNop(_): fatalError("Should never be serialized") @@ -1488,7 +1571,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) @@ -1500,7 +1585,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) } @@ -1559,6 +1645,18 @@ extension Instruction: ProtobufConvertible { $0.wasmBeginTypeGroup = Fuzzilli_Protobuf_WasmBeginTypeGroup() 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) + } + case .wasmDefineAdHocModuleSignatureType(let op): + $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) @@ -1579,7 +1677,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(_): @@ -1596,6 +1695,8 @@ extension Instruction: ProtobufConvertible { $0.wasmArraySet = Fuzzilli_Protobuf_WasmArraySet() case .wasmStructNewDefault(_): $0.wasmStructNewDefault = Fuzzilli_Protobuf_WasmStructNewDefault() + case .wasmStructNew(_): + $0.wasmStructNew = Fuzzilli_Protobuf_WasmStructNew() case .wasmStructGet(let op): $0.wasmStructGet = Fuzzilli_Protobuf_WasmStructGet.with { $0.fieldIndex = Int32(op.fieldIndex) @@ -1613,8 +1714,20 @@ extension Instruction: ProtobufConvertible { } case .wasmRefIsNull(_): $0.wasmRefIsNull = Fuzzilli_Protobuf_WasmRefIsNull() - case .wasmRefI31(_): - $0.wasmRefI31 = Fuzzilli_Protobuf_WasmRefI31() + case .wasmRefEq(_): + $0.wasmRefEq = Fuzzilli_Protobuf_WasmRefEq() + case .wasmRefTest(let op): + $0.wasmRefTest = Fuzzilli_Protobuf_WasmRefTest.with { + $0.type = ILTypeToWasmTypeEnum(op.type) + } + case .wasmRefCast(let op): + $0.wasmRefCast = Fuzzilli_Protobuf_WasmRefCast.with { + $0.type = ILTypeToWasmTypeEnum(op.type) + } + case .wasmRefI31(let op): + $0.wasmRefI31 = Fuzzilli_Protobuf_WasmRefI31.with { + $0.isShared = op.isShared + } case .wasmI31Get(let op): $0.wasmI31Get = Fuzzilli_Protobuf_WasmI31Get.with { $0.isSigned = op.isSigned @@ -1641,15 +1754,19 @@ 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] } 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 @@ -1679,101 +1796,109 @@ extension Instruction: ProtobufConvertible { fatalError("Unrecognized wasm value type \(value)") } case .refType(_): - let refKind: WasmReferenceType.Kind = switch wasmType.refType.kind { - case .index: - .Index() - case .externref: - .Abstract(.WasmExtern) - case .funcref: - .Abstract(.WasmFunc) - case .exnref: - .Abstract(.WasmExn) - case .i31Ref: - .Abstract(.WasmI31) - case .anyref: - .Abstract(.WasmAny) - case .eqref: - .Abstract(.WasmEq) - case .structref: - .Abstract(.WasmStruct) - case .arrayref: - .Abstract(.WasmArray) - case .noneref: - .Abstract(.WasmNone) - case .noexternref: - .Abstract(.WasmNoExtern) - case .nofuncref: - .Abstract(.WasmNoFunc) - case .noexnref: - .Abstract(.WasmNoExn) - case .UNRECOGNIZED(let value): - fatalError("Unrecognized wasm reference type \(value)") - } - return .wasmRef(refKind, nullability: wasmType.refType.nullability) + 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)") + } + 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") } } @@ -1807,18 +1932,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)") } } @@ -1827,25 +1954,28 @@ 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): - 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): 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) @@ -1876,7 +2006,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): @@ -1887,78 +2018,74 @@ 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): - 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 .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 .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: 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: @@ -1976,7 +2103,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): @@ -1984,13 +2113,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): @@ -1998,7 +2130,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: @@ -2012,7 +2145,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: @@ -2075,19 +2209,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): @@ -2103,15 +2243,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): @@ -2128,7 +2273,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): @@ -2140,13 +2287,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: @@ -2200,11 +2351,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: @@ -2229,15 +2382,22 @@ extension Instruction: ProtobufConvertible { op = BeginBlockStatement() case .endBlockStatement: op = EndBlockStatement() + case .beginBundleScript: + op = BeginBundleScript() + case .endBundleScript: + op = EndBundleScript() case .loadNewTarget: op = LoadNewTarget() 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 { @@ -2245,7 +2405,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): @@ -2274,22 +2436,24 @@ extension Instruction: ProtobufConvertible { op = Constf32(value: p.value) case .constf64(let p): op = Constf64(value: Float64(p.value)) - case .wasmReturn(let p): - op = WasmReturn(returnTypes: p.returnTypes.map(WasmTypeEnumToILType)) + case .wasmReturn(_): + op = WasmReturn(returnCount: inouts.count) case .wasmJsCall(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmJsCall(signature: parameters => outputs) + op = WasmJsCall(parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) // 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(_): @@ -2364,17 +2528,21 @@ extension Instruction: ProtobufConvertible { case .wasmTruncateSatf64Toi64(let p): op = WasmTruncateSatf64Toi64(isSigned: p.isSigned) - case .wasmReassign(let p): - op = WasmReassign(variableType: WasmTypeEnumToILType(p.variableType)) + 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(_): @@ -2385,41 +2553,39 @@ 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): 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) op = WasmCallIndirect(signature: parameters => outputs) case .wasmCallDirect(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmCallDirect(signature: parameters => outputs) + op = WasmCallDirect( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmReturnCallDirect(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmReturnCallDirect(signature: parameters => outputs) + op = WasmReturnCallDirect(parameterCount: Int(p.parameterCount)) case .wasmReturnCallIndirect(let p): let parameters = p.parameterTypes.map(WasmTypeEnumToILType) 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(_): @@ -2437,74 +2603,62 @@ 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): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginBlock(with: parameters => outputs) + op = WasmBeginBlock(parameterCount: Int(p.parameterCount)) case .wasmEndBlock(let p): - op = WasmEndBlock(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmEndBlock(outputCount: Int(p.outputCount)) case .wasmBeginLoop(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginLoop(with: parameters => outputs) + op = WasmBeginLoop(parameterCount: Int(p.parameterCount)) case .wasmEndLoop(let p): - op = WasmEndLoop(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmEndLoop(outputCount: Int(p.outputCount)) case .wasmBeginTryTable(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) let catches = p.catches.map(convertProtoWasmCatchKind) - op = WasmBeginTryTable(with: parameters => outputs, catches: catches) + op = WasmBeginTryTable(parameterCount: Int(p.parameterCount), catches: catches) case .wasmEndTryTable(let p): - op = WasmEndTryTable(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmEndTryTable(outputCount: Int(p.outputCount)) case .wasmBeginTry(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginTry(with: parameters => outputs) + op = WasmBeginTry(parameterCount: Int(p.parameterCount)) case .wasmBeginCatchAll(let p): - op = WasmBeginCatchAll(inputTypes: p.inputTypes.map(WasmTypeEnumToILType)) + op = WasmBeginCatchAll(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginCatch(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginCatch(with: parameters => outputs) + op = WasmBeginCatch( + blockOutputCount: Int(p.blockOutputCount), + labelParameterCount: Int(p.labelParameterCount)) case .wasmEndTry(let p): - op = WasmEndTry(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmEndTry(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginTryDelegate(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginTryDelegate(with: parameters => outputs) + op = WasmBeginTryDelegate(parameterCount: Int(p.parameterCount)) case .wasmEndTryDelegate(let p): - op = WasmEndTryDelegate(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) - case .wasmThrow(let p): - op = WasmThrow(parameterTypes: p.parameterTypes.map(WasmTypeEnumToILType)) + op = WasmEndTryDelegate(outputCount: Int(p.outputCount)) + case .wasmThrow(_): + op = WasmThrow(parameterCount: inouts.count - 1) case .wasmThrowRef(_): op = WasmThrowRef() case .wasmRethrow(_): op = WasmRethrow() - case .wasmDefineTag(let p): - op = WasmDefineTag(parameterTypes: p.parameterTypes.map(WasmTypeEnumToILType)) - case .wasmBranch(let p): - op = WasmBranch(labelTypes: p.parameters.map(WasmTypeEnumToILType)) + case .wasmDefineTag(_): + op = WasmDefineTag() + case .wasmBranch(_): + op = WasmBranch(parameterCount: inouts.count - 1) case .wasmBranchIf(let p): - op = WasmBranchIf(labelTypes: p.parameters.map(WasmTypeEnumToILType), 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(labelTypes: p.parameters.map(WasmTypeEnumToILType), valueCount: Int(p.valueCount)) + op = WasmBranchTable( + parameterCount: inouts.count - Int(p.valueCount) - 2, valueCount: Int(p.valueCount)) case .wasmBeginIf(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginIf(with: parameters => outputs, 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): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = WasmBeginElse(with: parameters => outputs) + op = WasmBeginElse( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmEndIf(let p): - op = WasmEndIf(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmEndIf(outputCount: Int(p.outputCount)) case .wasmNop(_): fatalError("Should never be deserialized!") case .wasmUnreachable(_): @@ -2512,7 +2666,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))! @@ -2539,37 +2693,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)) + case .wasmDefineAdHocModuleSignatureType(let p): + 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(_): @@ -2584,6 +2762,8 @@ extension Instruction: ProtobufConvertible { op = WasmArrayGet(isSigned: p.isSigned) case .wasmArraySet(_): op = WasmArraySet() + case .wasmStructNew(_): + op = WasmStructNew(fieldCount: inouts.count - 2) case .wasmStructNewDefault(_): op = WasmStructNewDefault() case .wasmStructGet(let p): @@ -2591,21 +2771,34 @@ 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 .wasmRefI31(_): - op = WasmRefI31() + case .wasmRefEq(_): + op = WasmRefEq() + case .wasmRefTest(let p): + op = WasmRefTest(refType: WasmTypeEnumToILType(p.type)) + case .wasmRefCast(let p): + op = WasmRefCast(refType: WasmTypeEnumToILType(p.type)) + case .wasmRefI31(let p): + op = WasmRefI31(isShared: p.isShared) 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(_): @@ -2613,12 +2806,13 @@ 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) - self.init(op, inouts: inouts, flags: .empty) + self.init(op, inouts: inouts) } init(from proto: ProtobufType) throws { diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 2ce2730fa..c7992206c 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. @@ -35,9 +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]() // Tracks the active function definitions and contains the instruction that started the function. private var activeFunctionDefinitions = Stack() @@ -62,7 +64,7 @@ public struct JSTyper: Analyzer { var functionImports: [(Variable, Signature)] = [] var functionDefines: [Variable] = [] - var globals : [Variable] { + var globals: [Variable] { return globalImports + globalDefines } @@ -122,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 }) } } @@ -171,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) } @@ -220,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 @@ -228,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 } @@ -267,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 { @@ -289,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) { @@ -306,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 @@ -322,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 @@ -338,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 @@ -356,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] = [] @@ -374,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 } @@ -392,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() { @@ -401,7 +454,8 @@ public struct JSTyper: Analyzer { state.reset() signatures.removeAll() typeGroups.removeAll() - defUseAnalyzer = DefUseAnalyzer() + wasmTypeDefMap.removeAll() + defUseAnalyzer = DefUseAnalyzer(isBundle: isBundle) isWithinTypeGroup = false dynamicObjectGroupManager = ObjectGroupManager() assert(activeFunctionDefinitions.isEmpty) @@ -410,7 +464,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. @@ -432,9 +487,29 @@ public struct JSTyper: Analyzer { } } - mutating func addSignatureType(def: Variable, signature: WasmSignature, inputs: ArraySlice) { + mutating func registerWasmTypeDef(_ def: Variable) { + let desc = type(of: def).wasmTypeDefinition!.description! + assert(wasmTypeDefMap[desc] == nil, "duplicate type description") + wasmTypeDefMap[desc] = def + } + + func getWasmTypeDef(for type: ILType) -> Variable { + assert(type.isWasmReferenceType) + guard case .Index(let desc) = type.wasmReferenceType!.kind else { + fatalError("\(type) is not an index type") + } + guard let desc = desc.get(), let typeDef = wasmTypeDefMap[desc] else { + fatalError("missing type definition link for type \(type), desc \(desc)") + } + return typeDef + } + + mutating func addSignatureType( + def: Variable, signature: WasmSignature, inputs: ArraySlice + ) { + assert(isWithinTypeGroup) var inputs = inputs.makeIterator() - let tgIndex = isWithinTypeGroup ? typeGroups.count - 1 : -1 + let tgIndex = typeGroups.count - 1 // Temporary variable to use by the resolveType capture. It would be nicer to use // higher-order functions for this but resolveType has to be a mutating func which doesn't @@ -444,24 +519,31 @@ public struct JSTyper: Analyzer { if paramType.requiredInputCount() == 0 { return paramType } - assert(paramType.Is(.wasmRef(.Index(), nullability: true))) + assert(paramType.Is(.anyIndexRef)) let typeDef = inputs.next()! let elementDesc = type(of: typeDef).wasmTypeDefinition!.description! 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 - params[i] = typer.type(of: replacement ?? def) + let nullability = params[i].wasmReferenceType!.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 }) } @@ -473,25 +555,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))) - if isWithinTypeGroup { - typeGroups[typeGroups.count - 1].append(def) - } + 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) { - let tgIndex = isWithinTypeGroup ? typeGroups.count - 1 : -1 + 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: @@ -504,60 +594,72 @@ 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))) - if isWithinTypeGroup { - typeGroups[typeGroups.count - 1].append(def) - } + 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?)]) { - let tgIndex = isWithinTypeGroup ? typeGroups.count - 1 : -1 + 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))) - if (isWithinTypeGroup) { - typeGroups[typeGroups.count - 1].append(def) - } + set( + def, + .wasmTypeDef( + description: WasmStructTypeDescription( + fields: resolvedFields, typeGroupIndex: tgIndex))) + typeGroups[typeGroups.count - 1].append(def) } func getTypeGroup(_ index: Int) -> [Variable] { @@ -587,12 +689,13 @@ public struct JSTyper: Analyzer { } } selfReferences.removeAll() - isWithinTypeGroup = false } 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 @@ -607,8 +710,10 @@ 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) { + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.outputTypes)) + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } } @@ -629,7 +734,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) @@ -640,61 +745,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 @@ -709,28 +814,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) @@ -738,31 +859,50 @@ public struct JSTyper: Analyzer { setType(of: instr.output, to: .wasmDataSegment(segmentLength: op.segment.count)) case .wasmDropDataSegment(_): type(of: instr.input(0)).wasmDataSegmentType!.markAsDropped() - case .wasmDefineTag(let op): - setType(of: instr.output, to: .object(ofGroup: "WasmTag", withWasmType: WasmTagType(op.parameterTypes))) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.output), forDefinition: instr, forVariable: instr.output) + 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) 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)) - case .wasmTableGet(let op): + dynamicObjectGroupManager.addWasmGlobal( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) + 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)) + 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)) @@ -781,93 +921,135 @@ 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) - case .wasmJsCall(let op): - let sigOutputTypes = op.functionSignature.outputTypes + 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") if !sigOutputTypes.isEmpty { setType(of: instr.output, to: sigOutputTypes[0]) } - let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) + 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(0)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(0)) - 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) + 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) case .wasmSelect(_): setType(of: instr.output, to: type(of: instr.input(0))) - case .wasmBeginBlock(let op): - wasmTypeBeginBlock(instr, op.signature) - case .wasmEndBlock(let op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginIf(let op): - wasmTypeBeginBlock(instr, op.signature) - case .wasmBeginElse(let op): + case .wasmBeginBlock(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) + case .wasmEndBlock(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, signature.outputTypes) + case .wasmBeginIf(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) + case .wasmBeginElse(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature // The else block is both end and begin block. - wasmTypeEndBlock(instr, op.signature.outputTypes) - wasmTypeBeginBlock(instr, op.signature) - case .wasmEndIf(let op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginLoop(let op): + wasmTypeEndBlock(instr, signature.outputTypes) + wasmTypeBeginBlock(instr, signature) + case .wasmEndIf(_): + 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 // 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.) - setType(of: instr.innerOutputs.first!, to: .label(op.signature.parameterTypes)) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(), op.signature.parameterTypes) { + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.parameterTypes)) + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } - case .wasmEndLoop(let op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginTryTable(let op): - wasmTypeBeginBlock(instr, op.signature) + case .wasmEndLoop(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, signature.outputTypes) + case .wasmBeginTryTable(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) 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 op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginTry(let op): - wasmTypeBeginBlock(instr, op.signature) - case .wasmBeginCatchAll(let op): - setType(of: instr.innerOutputs.first!, to: .label(op.inputTypes)) - case .wasmBeginCatch(let op): - let tagType = ILType.label(op.signature.outputTypes) - setType(of: instr.innerOutput(0), to: tagType) - let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - setType(of: instr.innerOutput(1), to: .exceptionLabel) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), op.signature.parameterTypes) { + case .wasmEndTryTable(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, signature.outputTypes) + case .wasmBeginTry(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) + case .wasmBeginCatchAll(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + 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: .wasmLabel(blockSignature.outputTypes)) + // Register the tag (Wasm exception) in the dynamicObjectGroupManager as being used + // by this Wasm module. + let tag = instr.input(1) + let definingInstruction = defUseAnalyzer.definition(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 + // exnref in the standard exception handling spec.) + 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. + 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, op.signature.outputTypes) { + for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) { setType(of: output, to: outputType) } - case .wasmEndTry(let op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginTryDelegate(let op): - wasmTypeBeginBlock(instr, op.signature) - case .wasmEndTryDelegate(let op): - wasmTypeEndBlock(instr, op.outputTypes) - case .wasmCallDirect(let op): - for (output, outputType) in zip(instr.outputs, op.signature.outputTypes) { + case .wasmEndTry(_): + let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, blockSignature.outputTypes) + case .wasmBeginTryDelegate(_): + let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, blockSignature) + case .wasmEndTryDelegate(_): + let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, blockSignature.outputTypes) + case .wasmCallDirect(_): + let signature = type(of: instr.input(0)).wasmFunctionDefSignature! + 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) @@ -876,13 +1058,14 @@ public struct JSTyper: Analyzer { setType(of: instr.output, to: typeDesc.elementType.unpacked()) case .wasmArraySet(_): break - case .wasmStructNewDefault(_): + case .wasmStructNew(_), + .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) @@ -891,18 +1074,43 @@ public struct JSTyper: Analyzer { } case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) - case .wasmRefI31(_): - setType(of: instr.output, to: .wasmRefI31) + case .wasmRefEq(_): + setType(of: instr.output, to: .wasmi32) + case .wasmRefI31(let op): + setType(of: instr.output, to: .wasmRefI31(shared: op.isShared)) case .wasmI31Get(_): setType(of: instr.output, to: .wasmi32) + case .wasmRefTest(_): + setType(of: instr.output, to: .wasmi32) + 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) + } else { + setType(of: instr.output, to: op.type) + } case .wasmAnyConvertExtern(_): + // TODO(pawkra): forward shared bit & update the comment // any.convert_extern forwards the nullability bit from the input. let null = type(of: instr.input(0)).wasmReferenceType!.nullability - setType(of: instr.output, to: .wasmRef(.Abstract(.WasmAny), nullability: null)) + setType(of: instr.output, to: .wasmRef(.WasmAny, shared: false, nullability: null)) case .wasmExternConvertAny(_): - // extern.convert_any forwards the nullability bit from the input. + // 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(.Abstract(.WasmExtern), 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) + finishTypeGroup() + registerWasmTypeDef(instr.output) + case .wasmDefineAdHocModuleSignatureType(let op): + startTypeGroup() + addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) + finishTypeGroup() + registerWasmTypeDef(instr.output) default: if instr.numInnerOutputs + instr.numOutputs != 0 { fatalError("Missing typing of outputs for \(instr.op.opcode)") @@ -964,7 +1172,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 @@ -974,7 +1184,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. @@ -997,9 +1209,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: @@ -1032,7 +1248,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() @@ -1057,8 +1275,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 @@ -1084,15 +1306,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): @@ -1105,18 +1334,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 @@ -1125,7 +1361,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) @@ -1138,13 +1377,15 @@ public struct JSTyper: Analyzer { } switch instr.op.opcode { case .beginObjectLiteral, - .endObjectLiteral, - .beginClassDefinition, - .endClassDefinition, - .beginClassStaticInitializer, - .endClassStaticInitializer, - .beginWasmModule, - .endWasmModule: + .endObjectLiteral, + .beginClassDefinition, + .endClassDefinition, + .beginClassStaticInitializer, + .endClassStaticInitializer, + .beginWasmModule, + .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: @@ -1172,12 +1413,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: @@ -1194,68 +1435,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, - .beginObjectLiteralSetter, - .beginPlainFunction, - .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor, - .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .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, - .endObjectLiteralSetter, - .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endConstructor, - .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .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). // @@ -1267,7 +1506,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 { @@ -1276,13 +1516,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)) } } } @@ -1290,61 +1537,75 @@ 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 - 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) } @@ -1355,7 +1616,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) { @@ -1375,26 +1638,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]) } } @@ -1417,8 +1682,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) @@ -1456,7 +1722,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) @@ -1484,24 +1750,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 @@ -1509,13 +1780,26 @@ 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) 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)) + case .endObjectLiteral: let instanceType = dynamicObjectGroupManager.finalizeObjectLiteral() set(instr.output, instanceType) @@ -1527,80 +1811,122 @@ 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) + 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) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) + 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)) - 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) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + 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 .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 - 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): - // 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)) + 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 .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + 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, - .createIntArray, - .createFloatArray, - .createArrayWithSpread: + .createIntArray, + .createFloatArray, + .createArrayWithSpread: set(instr.output, .jsArray) case .createTemplateString: @@ -1622,18 +1948,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: @@ -1641,11 +1967,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): @@ -1653,18 +1979,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: @@ -1712,10 +2041,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) { @@ -1757,20 +2086,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: @@ -1784,7 +2118,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) @@ -1825,26 +2159,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" @@ -1852,7 +2206,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. @@ -1882,21 +2237,27 @@ 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() + for output in instr.outputs { + registerWasmTypeDef(output) + } case .wasmDefineSignatureType(let op): addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) 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 { @@ -1925,7 +2286,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: @@ -2052,7 +2415,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. @@ -2070,7 +2437,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. @@ -2095,7 +2465,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 @@ -2104,7 +2476,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]! } @@ -2118,8 +2492,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) } @@ -2139,7 +2516,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. @@ -2182,8 +2560,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 @@ -2193,17 +2576,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. @@ -2281,7 +2669,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 d8dcbe154..14e74f42d 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") } @@ -149,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]) } } @@ -272,7 +302,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 +334,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 +436,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 +561,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 +589,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 +606,11 @@ 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 + parameters.numDefaultParameters, + numInnerOutputs: parameters.count + 1, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -588,7 +627,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]) } } @@ -596,6 +638,23 @@ 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) } @@ -605,7 +664,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]) } } @@ -613,6 +675,23 @@ 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) } @@ -679,7 +758,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) } } @@ -688,7 +769,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]) } } @@ -696,145 +780,172 @@ 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 - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + 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 - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + 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]) + 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]) + super.init( + parameters: parameters, numInputs: 1 + parameters.numDefaultParameters, + 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]) + 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) } - - let propertyName: String +final class BeginClassComputedGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedGetter(self) } + let isStatic: Bool - init(propertyName: String) { - self.propertyName = propertyName + init(isStatic: Bool) { + 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]) + // 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 EndClassInstanceSetter: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceSetter(self) } +final class EndClassComputedGetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedGetter(self) } } -final class ClassAddStaticProperty: JsOperation { - override var opcode: Opcode { .classAddStaticProperty(self) } +final class BeginClassSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassSetter(self) } let propertyName: String - var hasValue: Bool { - return numInputs == 1 - } + let isStatic: Bool - init(propertyName: String, hasValue: Bool) { + init(propertyName: String, isStatic: Bool) { self.propertyName = propertyName - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + 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 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 EndClassSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassSetter(self) } } -final class ClassAddStaticComputedProperty: JsOperation { - override var opcode: Opcode { .classAddStaticComputedProperty(self) } +final class BeginClassComputedSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedSetter(self) } + let isStatic: Bool - var hasValue: Bool { - return numInputs == 2 + 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]) } +} - init(hasValue: Bool) { - super.init(numInputs: hasValue ? 2 : 1, requiredContext: .classDefinition) - } +final class EndClassComputedSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedSetter(self) } } final class BeginClassStaticInitializer: JsOperation { @@ -843,7 +954,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]) } } @@ -855,130 +968,44 @@ 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) } +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. - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + // 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 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) } - - 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 EndClassPrivateStaticMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassPrivateStaticMethod(self) } +final class EndClassPrivateMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassPrivateMethod(self) } } final class EndClassDefinition: JsOperation { @@ -997,7 +1024,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]) } } @@ -1035,7 +1064,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) } } @@ -1052,7 +1082,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]) } } @@ -1109,9 +1141,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)) @@ -1292,15 +1324,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 } } @@ -1310,11 +1359,18 @@ 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? = 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) + super.init( + numInputs: numInputs ?? parameters.numDefaultParameters, numOutputs: numOutputs, + numInnerOutputs: numInnerOutputs, attributes: attributes, + requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -1329,11 +1385,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: parameters.numDefaultParameters, + numOutputs: 1, + numInnerOutputs: parameters.count, + contextOpened: contextOpened) } } class EndAnyFunction: EndAnySubroutine {} @@ -1347,7 +1404,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) @@ -1375,7 +1435,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 { @@ -1387,7 +1449,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 { @@ -1399,7 +1463,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 { @@ -1411,7 +1476,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 { @@ -1425,7 +1492,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 { @@ -1467,7 +1536,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]) } } @@ -1481,7 +1552,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]) } } @@ -1490,7 +1563,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]) } } @@ -1498,7 +1572,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]) } } @@ -1511,7 +1587,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]) } } @@ -1529,7 +1607,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]) } } @@ -1542,7 +1622,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]) } } @@ -1560,7 +1642,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]) } } @@ -1576,7 +1660,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]) } } @@ -1596,7 +1682,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]) } } @@ -1609,7 +1697,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]) } } @@ -1627,19 +1717,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: [" "]) @@ -1666,19 +1758,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 = "??" @@ -1748,6 +1840,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") self.indices = indices self.lastIsRest = lastIsRest super.init(numInputs: 1, numOutputs: indices.count) @@ -1761,9 +1856,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") self.indices = indices self.lastIsRest = lastIsRest // The first input is the array being destructed @@ -1793,7 +1891,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 @@ -1803,13 +1901,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 { @@ -1850,7 +1948,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]) } } @@ -1870,7 +1970,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]) } } @@ -1885,7 +1987,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]) } } @@ -1942,7 +2046,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]) } } @@ -1984,7 +2090,6 @@ final class GetComputedSuperProperty: JsOperation { } } - final class UpdateSuperProperty: JsOperation { override var opcode: Opcode { .updateSuperProperty(self) } @@ -2006,7 +2111,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) } } @@ -2014,7 +2121,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) } } @@ -2071,7 +2180,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) } } @@ -2080,7 +2190,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]) } } @@ -2096,7 +2208,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]) } } @@ -2104,7 +2218,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) } } @@ -2153,7 +2269,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) } } @@ -2165,7 +2282,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) } } @@ -2177,7 +2297,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) } } @@ -2189,7 +2312,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]) } } @@ -2205,7 +2331,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]) } } @@ -2221,7 +2350,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]) } } @@ -2235,7 +2367,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]) } } @@ -2263,7 +2398,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]) } } @@ -2303,7 +2441,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]) } } @@ -2353,7 +2493,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) } } @@ -2427,7 +2568,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]) } } @@ -2438,7 +2581,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]) } } @@ -2479,10 +2624,29 @@ 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() { - super.init(numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], contextOpened: [.wasm]) + super.init( + numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], + contextOpened: [.wasm]) } } @@ -2529,7 +2693,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) } } @@ -2550,14 +2715,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. @@ -2568,7 +2733,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]) } } @@ -2591,13 +2757,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]) } } @@ -2608,21 +2775,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]) } } @@ -2647,7 +2817,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]) } } @@ -2697,7 +2868,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 @@ -2714,7 +2887,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) @@ -2738,7 +2913,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/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index f9fda2f00..deb4011bc 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) @@ -363,4 +349,20 @@ enum Opcode { case wasmDefineSignatureType(WasmDefineSignatureType) case createNamedDisposableVariable(CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(CreateNamedAsyncDisposableVariable) + case wasmDefineAdHocSignatureType(WasmDefineAdHocSignatureType) + case wasmStructNew(WasmStructNew) + case wasmRefEq(WasmRefEq) + 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) + case beginBundleScript(BeginBundleScript) + case endBundleScript(EndBundleScript) } 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..7b151998d 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -47,19 +47,22 @@ 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 } /// 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 } /// 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) @@ -138,6 +141,7 @@ extension Program: ProtobufConvertible { if let parent = parent { $0.parent = parent.asProtobuf(opCache: opCache) } + $0.isBundle = code.isBundle } } @@ -146,19 +150,21 @@ 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)) } 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 968003082..325524ca3 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) } @@ -138,34 +137,32 @@ 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 + 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 .beginClassComputedGetter: + return endOp is EndClassComputedGetter + case .beginClassSetter: + return endOp is EndClassSetter + case .beginClassComputedSetter: + return endOp is EndClassComputedSetter 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: @@ -189,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 @@ -210,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 @@ -224,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: @@ -235,7 +234,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 be22285c9..a19b294c1 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,23 +151,40 @@ 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, + 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 /// 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,47 +211,71 @@ 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) } // Internal types // 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))) + public static func wasmLabel(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { + return ILType( + definiteType: .wasmLabel, + 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 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 { + 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,38 +288,86 @@ 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 let wasmExternRef = ILType.wasmRef(.Abstract(.WasmExtern), nullability: true) - public static let wasmRefExtern = ILType.wasmRef(.Abstract(.WasmExtern), nullability: false) - public static let wasmFuncRef = ILType.wasmRef(.Abstract(.WasmFunc), nullability: true) - public static let wasmExnRef = ILType.wasmRef(.Abstract(.WasmExn), nullability: true) - public static let wasmI31Ref = ILType.wasmRef(.Abstract(.WasmI31), nullability: true) - public static let wasmRefI31 = ILType.wasmRef(.Abstract(.WasmI31), nullability: false) - public static let wasmAnyRef = ILType.wasmRef(.Abstract(.WasmAny), nullability: true) - public static let wasmRefAny = ILType.wasmRef(.Abstract(.WasmAny), nullability: false) - public static let wasmNullRef = ILType.wasmRef(.Abstract(.WasmNone), nullability: true) - public static let wasmNullExternRef = ILType.wasmRef(.Abstract(.WasmNoExtern), nullability: true) - public static let wasmNullFuncRef = ILType.wasmRef(.Abstract(.WasmNoFunc), nullability: true) - public static let wasmEqRef = ILType.wasmRef(.Abstract(.WasmEq), nullability: true) - public static let wasmStructRef = ILType.wasmRef(.Abstract(.WasmStruct), nullability: true) - public static let wasmArrayRef = ILType.wasmRef(.Abstract(.WasmArray), 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) + public static func allNullableAbstractWasmRefTypes() -> [ILType] { + var refTypes: [ILType] = [] + for sharedRef in [true, false] { + for heapType in WasmAbstractHeapType.allCases { + refTypes.append(wasmRef(heapType, shared: sharedRef, nullability: true)) + } + } + return refTypes + } + 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 { + .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 { @@ -286,11 +375,13 @@ public struct ILType: Hashable { } // The union of all primitive wasm types - public static let wasmPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmExternRef | .wasmFuncRef | .wasmI31Ref | .wasmSimd128 | .wasmGenericRef + public static let wasmPrimitive = + .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef public static let wasmNumericalPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 public static let anyNonNullableIndexRef = wasmRef(.Index(), nullability: false) + public static let anyIndexRef = wasmRef(.Index(), nullability: true) // // Type testing @@ -317,10 +408,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) } @@ -379,13 +471,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 } } @@ -409,7 +506,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 } @@ -422,13 +520,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 } @@ -448,15 +550,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 } } @@ -464,15 +578,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 // @@ -494,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? { @@ -529,7 +642,6 @@ public struct ILType: Hashable { return wasmMemoryType != nil && ext?.group == "WasmMemory" } - public var wasmDataSegmentType: WasmDataSegmentType? { return ext?.wasmExt as? WasmDataSegmentType } @@ -546,7 +658,6 @@ public struct ILType: Hashable { return wasmElementSegmentType != nil } - public var wasmTableType: WasmTableType? { return ext?.wasmExt as? WasmTableType } @@ -596,8 +707,18 @@ public struct ILType: Hashable { return (wasmType as! WasmFunctionDefinition).signature } + public var wasmFunctionSignatureDefSignature: WasmSignature { + let desc = (wasmType as? WasmTypeDefinition)?.description + guard let desc = desc as? WasmSignatureTypeDescription else { + fatalError("\(self) is not a Wasm signature type defintion") + } + return desc.signature + } + public var isWasmDefaultable: Bool { - return Is(.wasmPrimitive) && !(isWasmReferenceType && !wasmReferenceType!.nullability) + let isPacked = Is(.wasmPackedI8) || Is(.wasmPackedI16) + return isPacked + || (Is(.wasmPrimitive) && (!isWasmReferenceType || wasmReferenceType!.nullability)) } public var properties: Set { @@ -634,8 +755,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 @@ -650,7 +771,6 @@ public struct ILType: Hashable { return isPacked() ? .wasmi32 : self } - // // Type operations // @@ -667,13 +787,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 } @@ -692,25 +816,34 @@ 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. 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)) + return ILType( + definiteType: definiteType, possibleType: possibleType, + ext: TypeExtension( + group: group, properties: commonProperties, methods: commonMethods, + signature: signature, wasmExt: wasmExt, receiver: receiver, + isEnumeration: isEnumeration)) } - 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 } @@ -769,39 +902,54 @@ 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)) + 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, isEnumeration: isEnumeration)) } - 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 } @@ -813,12 +961,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 } @@ -833,7 +983,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 } @@ -862,16 +1015,21 @@ 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) + let ext = TypeExtension( + group: group, properties: self.properties.union(other.properties), + methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, + receiver: receiver, isEnumeration: isEnumeration) 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) } @@ -888,7 +1046,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, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -908,7 +1068,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, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -919,7 +1081,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, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -935,7 +1099,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, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -943,7 +1109,9 @@ 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, + isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1061,7 +1229,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: @@ -1076,24 +1245,25 @@ 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" } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapType): - return ".wasmRef(.Abstract(\(nullPrefix)\(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 { @@ -1106,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: @@ -1145,35 +1315,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 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) + static let wasmSimd128 = BaseType(rawValue: 1 << 18) static let wasmFunctionDef = BaseType(rawValue: 1 << 19) // Wasm-gc types @@ -1189,11 +1359,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 { @@ -1215,8 +1395,16 @@ 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 { + // 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, isEnumeration: Bool = false + ) { + if group == nil && properties.isEmpty && methods.isEmpty && signature == nil + && wasmExt == nil && receiver == nil + { return nil } @@ -1226,15 +1414,17 @@ class TypeExtension: Hashable { self.signature = signature self.wasmExt = wasmExt self.receiver = receiver + self.isEnumeration = isEnumeration } - 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 && lhs.signature == rhs.signature && lhs.wasmExt == rhs.wasmExt && lhs.receiver == rhs.receiver + && lhs.isEnumeration == rhs.isEnumeration } public func hash(into hasher: inout Hasher) { @@ -1244,13 +1434,14 @@ class TypeExtension: Hashable { hasher.combine(signature) hasher.combine(wasmExt) hasher.combine(receiver) + hasher.combine(isEnumeration) } } // 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) } @@ -1366,7 +1557,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 } @@ -1389,9 +1580,8 @@ public class WasmTypeDefinition: WasmTypeExtension { } // TODO: Add continuation types for core stack switching. -// TODO: Add shared bit for shared-everything-threads. // TODO: Add internal string type for JS string builtins. -enum WasmAbstractHeapType: CaseIterable, Comparable { +public enum WasmAbstractHeapType: CaseIterable, Comparable { // Note: The union, intersection, ... implementations are inspired by Binaryen's implementation, // so when extending the type system, feel free to use that implemenation as an orientation. // https://github.com/WebAssembly/binaryen/blob/main/src/wasm/wasm-type.cpp @@ -1413,10 +1603,10 @@ 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 } } @@ -1426,14 +1616,14 @@ 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 } } @@ -1458,14 +1648,14 @@ 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)") } } @@ -1473,8 +1663,8 @@ enum WasmAbstractHeapType: CaseIterable, Comparable { if self == other { return self } - if self.getBottom() != other.getBottom() { - return nil + if !self.inSameHierarchy(other) { + return nil // Incompatible heap types. } if self.subsumes(other) { return other @@ -1488,10 +1678,60 @@ enum WasmAbstractHeapType: CaseIterable, Comparable { func subsumes(_ other: Self) -> Bool { union(other) == self } + + public static func allNonBottomTypes() -> [WasmAbstractHeapType] { + return WasmAbstractHeapType.allCases.filter { !$0.isBottom() } + } +} + +public class HeapTypeInfo: Hashable { + public let heapType: WasmAbstractHeapType + public let shared: Bool + + init(_ heapType: WasmAbstractHeapType, shared: Bool) { + self.heapType = heapType + self.shared = shared + } + + 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 let unionHeapType = heapType.union(other.heapType) { + return HeapTypeInfo(unionHeapType, shared: shared) + } + return nil + } + + func intersection(_ other: HeapTypeInfo) -> HeapTypeInfo? { + if shared != other.shared { + return nil + } + if let intersectionHeapType = heapType.intersection(other.heapType) { + return HeapTypeInfo(intersectionHeapType, shared: shared) + } + return nil + } + + func subsumes(_ other: HeapTypeInfo) -> Bool { + if shared != other.shared { + return false + } + return heapType.subsumes(other.heapType) + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(heapType) + hasher.combine(shared) + } } // A wrapper around a WasmTypeDescription without owning the WasmTypeDescription. -struct UnownedWasmTypeDescription : Hashable { +struct UnownedWasmTypeDescription: Hashable { private unowned var description: WasmTypeDescription? init(_ description: WasmTypeDescription? = nil) { @@ -1504,7 +1744,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 @@ -1512,72 +1752,78 @@ public class WasmReferenceType: WasmTypeExtension { // corresponding WasmTypeDefinition extension attached to the type of the operation // defining the wasm-gc type (and is kept alive by the JSTyper). case Index(UnownedWasmTypeDescription = UnownedWasmTypeDescription()) - case Abstract(WasmAbstractHeapType) + case Abstract(HeapTypeInfo) 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()) + } + 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 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) - } + 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 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) - } + } + 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 } @@ -1592,10 +1838,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 } } @@ -1648,7 +1894,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) { @@ -1732,7 +1979,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) { @@ -1742,7 +1990,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 @@ -1758,18 +2009,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)) @@ -1793,18 +2048,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) { @@ -1842,11 +2097,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)") } } } @@ -2009,11 +2264,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) } } @@ -2033,7 +2288,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)]" } @@ -2051,7 +2307,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) } @@ -2066,10 +2322,10 @@ class WasmTypeDescription: Hashable, CustomStringConvertible { // The "closest" super type that is an abstract type (.WasmArray for arrays, .WasmStruct for // structs). It is nil for unresolved forward/self references for which the concrete abstract // super type is still undecided. - public let abstractHeapSupertype: WasmAbstractHeapType? + public let abstractHeapSupertype: HeapTypeInfo? // TODO(gc): We will also need to support subtyping of struct and array types at some point. - init(typeGroupIndex: Int, superType: WasmAbstractHeapType? = nil) { + init(typeGroupIndex: Int, superType: HeapTypeInfo? = nil) { self.typeGroupIndex = typeGroupIndex self.abstractHeapSupertype = superType } @@ -2099,7 +2355,9 @@ class WasmSignatureTypeDescription: WasmTypeDescription { init(signature: WasmSignature, typeGroupIndex: Int) { self.signature = signature - super.init(typeGroupIndex: typeGroupIndex, superType: .WasmFunc) + // TODO(pawkra): support shared variant. + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2107,8 +2365,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)]]" } } @@ -2120,7 +2378,9 @@ class WasmArrayTypeDescription: WasmTypeDescription { init(elementType: ILType, mutability: Bool, typeGroupIndex: Int) { self.elementType = elementType self.mutability = mutability - super.init(typeGroupIndex: typeGroupIndex, superType: .WasmArray) + // TODO(pawkra): support shared variant. + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2151,7 +2411,10 @@ class WasmStructTypeDescription: WasmTypeDescription { init(fields: [Field], typeGroupIndex: Int) { self.fields = fields - super.init(typeGroupIndex: typeGroupIndex, superType: .WasmStruct) + // TODO(pawkra): support shared variant. + 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 bed8bd6ae..113cd8e3f 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 { @@ -74,11 +73,9 @@ final class Constf64: WasmOperation { final class WasmReturn: WasmOperation { override var opcode: Opcode { .wasmReturn(self) } - let returnTypes: [ILType] - init(returnTypes: [ILType]) { - self.returnTypes = returnTypes - super.init(numInputs: returnTypes.count, attributes: [.isJump], requiredContext: [.wasmFunction]) + init(returnCount: Int) { + super.init(numInputs: returnCount, attributes: [.isJump], requiredContext: [.wasmFunction]) } } @@ -91,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 @@ -126,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]) } } @@ -136,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]) } } @@ -172,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]) } } @@ -182,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]) } } @@ -240,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]) } } @@ -250,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]) } } @@ -306,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 } } @@ -325,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 } } @@ -359,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]) } } @@ -369,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]) } } @@ -407,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]) } } @@ -417,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]) } } @@ -695,6 +704,7 @@ public enum WasmGlobal { case wasmf64(Float64) // Empty reference // TODO(gc): Add support for globals with non-nullable references. + // TODO(pawkra): add support for shared references. case externref case exnref case i31ref @@ -704,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: @@ -716,11 +725,11 @@ public enum WasmGlobal { case .wasmf64: return .wasmf64 case .externref: - return .wasmExternRef + return .wasmExternRef() case .exnref: - return .wasmExnRef + return .wasmExnRef() case .i31ref: - return .wasmI31Ref + return .wasmI31Ref() case .imported(let type): assert(type.wasmGlobalType != nil) return type.wasmGlobalType!.valueType @@ -764,7 +773,7 @@ public enum WasmGlobal { case .externref: return "" case .exnref, - .i31ref: + .i31ref: return "null" default: fatalError("Unimplemented / unhandled") @@ -794,19 +803,24 @@ 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 self.definedEntries = definedEntries // TODO(manoskouk): Find a way to define non-function tables with initializers. - assert(elementType == .wasmFuncRef || definedEntries.isEmpty) + let isWasmFuncRef = elementType == .wasmFuncRef() + assert(isWasmFuncRef || definedEntries.isEmpty) - super.init(numInputs: elementType == .wasmFuncRef ? definedEntries.count : 0, - numOutputs: 1, - attributes: [.isMutable], - requiredContext: [.wasm]) + super.init( + numInputs: isWasmFuncRef ? definedEntries.count : 0, + numOutputs: 1, + attributes: [.isMutable], + requiredContext: [.wasm]) } } @@ -876,11 +890,10 @@ final class WasmDefineDataSegment: WasmOperation { final class WasmDefineTag: WasmOperation { override var opcode: Opcode { .wasmDefineTag(self) } - public let parameterTypes: [ILType] - init(parameterTypes: [ILType]) { - self.parameterTypes = parameterTypes - super.init(numOutputs: 1, attributes: [], requiredContext: [.wasm]) + init() { + // Inputs: The signature. + super.init(numInputs: 1, numOutputs: 1, attributes: [], 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]) } } @@ -912,12 +927,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 +935,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]) } } @@ -956,28 +962,34 @@ 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]) } } final class WasmCallDirect: WasmOperation { override var opcode: Opcode { .wasmCallDirect(self) } - let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInputs: 1 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, requiredContext: [.wasmFunction]) + init(parameterCount: Int, outputCount: Int) { + super.init( + numInputs: 1 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } + + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallDirect: WasmOperation { override var opcode: Opcode { .wasmReturnCallDirect(self) } - let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInputs: 1 + signature.parameterTypes.count, numOutputs: 0, attributes: [.isJump], requiredContext: [.wasmFunction]) + init(parameterCount: Int) { + super.init( + numInputs: 1 + parameterCount, numOutputs: 0, attributes: [.isJump], + requiredContext: [.wasmFunction]) } + + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallIndirect: WasmOperation { @@ -986,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]) } } @@ -1021,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 } } } @@ -1052,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]) } } @@ -1067,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 } } } @@ -1225,12 +1240,14 @@ final class WasmDropDataSegment: WasmOperation { final class WasmJsCall: WasmOperation { override var opcode: Opcode { .wasmJsCall(self) } - let functionSignature: WasmSignature - - init(signature: WasmSignature) { - self.functionSignature = signature - super.init(numInputs: 1 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, requiredContext: [.wasmFunction]) + init(parameterCount: Int, outputCount: Int) { + super.init( + numInputs: 2 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } + + var parameterCount: Int { numInputs - 2 } + var outputCount: Int { numOutputs } } final class WasmSelect: WasmOperation { @@ -1247,26 +1264,29 @@ final class WasmSelect: WasmOperation { final class WasmBeginBlock: WasmOperation { override var opcode: Opcode { .wasmBeginBlock(self) } - let signature: WasmSignature - - init(with signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.parameterTypes.count, numInnerOutputs: signature.parameterTypes.count + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + 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]) } + + var parameterCount: Int { numInputs - 1 } } final class WasmEndBlock: WasmOperation { override var opcode: Opcode { .wasmEndBlock(self) } - let outputTypes: [ILType] - - init(outputTypes: [ILType]) { - self.outputTypes = outputTypes - super.init(numInputs: outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + init(outputCount: Int) { + 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,69 +1294,90 @@ public enum WasmBranchHint: CaseIterable { final class WasmBeginIf: WasmOperation { override var opcode: Opcode { .wasmBeginIf(self) } - let signature: WasmSignature let inverted: Bool let hint: WasmBranchHint - init(with signature: WasmSignature = [] => [], hint: WasmBranchHint = .None, inverted: Bool = false) { - self.signature = signature + init(parameterCount: Int = 0, hint: WasmBranchHint = .None, inverted: Bool = false) { self.inverted = inverted self.hint = hint // Note that the condition is the last input! This is due to how lifting works for the wasm // value stack and that the condition is the first value to be removed from the stack, so // 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: signature.parameterTypes.count + 1, numInnerOutputs: 1 + signature.parameterTypes.count, 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 } } final class WasmBeginElse: WasmOperation { override var opcode: Opcode { .wasmBeginElse(self) } - let signature: WasmSignature - init(with signature: WasmSignature = [] => []) { - self.signature = signature + // The parameterCount and outputCount of the wasm signature. + init(parameterCount: Int = 0, outputCount: Int = 0) { // 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: signature.outputTypes.count, numInnerOutputs: 1 + signature.parameterTypes.count, 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 } } final class WasmEndIf: WasmOperation { override var opcode: Opcode { .wasmEndIf(self) } - let outputTypes: [ILType] - init(outputTypes: [ILType] = []) { - self.outputTypes = outputTypes - super.init(numInputs: outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + init(outputCount: Int = 0) { + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd], + requiredContext: [.wasmFunction]) } + + var outputCount: Int { numInputs - 1 } } final class WasmBeginLoop: WasmOperation { override var opcode: Opcode { .wasmBeginLoop(self) } - let signature: WasmSignature - init(with signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.parameterTypes.count, numInnerOutputs: 1 + signature.parameterTypes.count, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + 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]) + } + + convenience init(with signature: WasmSignature) { + self.init(parameterCount: signature.parameterTypes.count) } + + var parameterCount: Int { numInputs - 1 } } final class WasmEndLoop: WasmOperation { override var opcode: Opcode { .wasmEndLoop(self) } - let outputTypes: [ILType] - init(outputTypes: [ILType] = []) { - self.outputTypes = outputTypes - super.init(numInputs: outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + init(outputCount: Int) { + // Inputs: the signature + the outputs of the loop. + 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 @@ -1344,75 +1385,81 @@ final class WasmBeginTryTable: WasmOperation { } override var opcode: Opcode { .wasmBeginTryTable(self) } - let signature: WasmSignature let catches: [CatchKind] - init(with signature: WasmSignature, catches: [CatchKind]) { - self.signature = signature + 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: signature.parameterTypes.count + inputLabelCount + inputTagCount , numInnerOutputs: signature.parameterTypes.count + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount + inputLabelCount + inputTagCount, + numInnerOutputs: parameterCount + 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } + + var parameterCount: Int { numInnerOutputs - 1 } } final class WasmEndTryTable: WasmOperation { override var opcode: Opcode { .wasmEndTryTable(self) } - let outputTypes: [ILType] - init(outputTypes: [ILType]) { - self.outputTypes = outputTypes - super.init(numInputs: outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + init(outputCount: Int) { + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } final class WasmBeginTry: WasmOperation { override var opcode: Opcode { .wasmBeginTry(self) } - let signature: WasmSignature - init(with signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.parameterTypes.count, numInnerOutputs: signature.parameterTypes.count + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + init(parameterCount: Int) { + // Inputs: The block signature and the block arguments. + // Inner outputs: The label and the block parameters. + 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) } - let inputTypes: [ILType] - - init(inputTypes: [ILType]) { - self.inputTypes = inputTypes + init(blockOutputCount: Int) { + // Inputs: The block signature and the outputs of the preceding try or catch block. super.init( - numInputs: inputTypes.count, - numInnerOutputs: 1, // the label + numInputs: 1 + blockOutputCount, + 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) } - let signature: WasmSignature - init(with signature: WasmSignature) { - self.signature = signature + init(blockOutputCount: Int, labelParameterCount: Int) { // TODO: In an ideal world, the catch would only have one label that is used both for // 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( - numInputs: 1 + signature.outputTypes.count, + // Inputs: The block signature, the tag, the tag signature, and the outputs of the preceding try or catch + // (all) block. + numInputs: 3 + blockOutputCount, // Inner outputs are the branch label, the exception label and the tag parameters. - numInnerOutputs: 2 + signature.parameterTypes.count, + numInnerOutputs: 2 + labelParameterCount, attributes: [ .isBlockEnd, .isBlockStart, @@ -1420,26 +1467,32 @@ final class WasmBeginCatch : WasmOperation { ], requiredContext: [.wasmFunction]) } + + var blockOutputCount: Int { numInputs - 3 } + var labelParameterCount: Int { numInnerOutputs - 2 } } final class WasmEndTry: WasmOperation { override var opcode: Opcode { .wasmEndTry(self) } - let outputTypes: [ILType] - init(outputTypes: [ILType] = []) { - self.outputTypes = outputTypes - super.init(numInputs: outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + init(blockOutputCount: Int) { + super.init( + numInputs: 1 + blockOutputCount, numOutputs: blockOutputCount, + attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) } } /// A special try block that does not have any catch / catch_all handlers but ends with a delegate to handle the exception. final class WasmBeginTryDelegate: WasmOperation { override var opcode: Opcode { .wasmBeginTryDelegate(self) } - let signature: WasmSignature - init(with signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.parameterTypes.count, numInnerOutputs: 1 + signature.parameterTypes.count, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction], contextOpened: []) + init(parameterCount: Int) { + // inputs: The signature and the arguments. + // innerOutputs: The label and the arguments. + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } } @@ -1447,23 +1500,23 @@ final class WasmBeginTryDelegate: WasmOperation { /// This can be a "proper" try block (in which case its catch blocks apply) or any other block like a loop or an if. final class WasmEndTryDelegate: WasmOperation { override var opcode: Opcode { .wasmEndTryDelegate(self) } - let outputTypes: [ILType] - init(outputTypes: [ILType] = []) { - self.outputTypes = outputTypes - // Inputs: 1 label to delegate an exception to plus all the outputs of the try block. - super.init(numInputs: 1 + outputTypes.count, numOutputs: outputTypes.count, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + 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, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } final class WasmThrow: WasmOperation { override var opcode: Opcode { .wasmThrow(self) } - public let parameterTypes: [ILType] - init(parameterTypes: [ILType]) { - self.parameterTypes = parameterTypes + init(parameterCount: Int) { // Inputs: the tag to be thrown plus the arguments for each parameter type of the tag. - super.init(numInputs: 1 + parameterTypes.count, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, attributes: [.isJump], requiredContext: [.wasmFunction]) } } @@ -1487,40 +1540,42 @@ final class WasmRethrow: WasmOperation { final class WasmBranch: WasmOperation { override var opcode: Opcode { .wasmBranch(self) } - let labelTypes: [ILType] - - init(labelTypes: [ILType]) { - self.labelTypes = labelTypes - super.init(numInputs: 1 + labelTypes.count, requiredContext: [.wasmFunction]) + init(parameterCount: Int) { + super.init(numInputs: 1 + parameterCount, requiredContext: [.wasmFunction]) } + + var parameterCount: Int { numInputs - 1 } } final class WasmBranchIf: WasmOperation { override var opcode: Opcode { .wasmBranchIf(self) } - let labelTypes: [ILType] let hint: WasmBranchHint - init(labelTypes: [ILType], hint: WasmBranchHint) { - self.labelTypes = labelTypes + init(parameterCount: Int, hint: WasmBranchHint) { self.hint = hint // The inputs are the label, the arguments and the condition. - super.init(numInputs: 1 + labelTypes.count + 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount + 1, attributes: [.isMutable], + requiredContext: [.wasmFunction]) } + + var parameterCount: Int { numInputs - 2 } } final class WasmBranchTable: WasmOperation { override var opcode: Opcode { .wasmBranchTable(self) } - let labelTypes: [ILType] // The number of cases in the br_table. Note that the number of labels is one higher as each // br_table has a default label. let valueCount: Int - init(labelTypes: [ILType], valueCount: Int) { - self.labelTypes = labelTypes + init(parameterCount: Int, valueCount: Int) { self.valueCount = valueCount - super.init(numInputs: valueCount + 1 + labelTypes.count + 1, requiredContext: [.wasmFunction]) + // Inputs: the case labels, the default label, the arguments and the condition. + super.init(numInputs: valueCount + 1 + parameterCount + 1, requiredContext: [.wasmFunction]) } + + 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. @@ -1528,10 +1583,7 @@ final class WasmBranchTable: WasmOperation { final class WasmReassign: WasmOperation { override var opcode: Opcode { .wasmReassign(self) } - let variableType: ILType - - init(variableType: ILType) { - self.variableType = variableType + init() { super.init(numInputs: 2, attributes: [.isNotInputMutable], requiredContext: [.wasmFunction]) } } @@ -1544,22 +1596,26 @@ 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. @@ -1571,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]) } } @@ -1587,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]) } } @@ -1619,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 } } } @@ -1648,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]) } } @@ -1662,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 } @@ -1711,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]) } } @@ -1722,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 } } @@ -1765,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 } } } @@ -1804,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]) } } @@ -1820,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 } } } @@ -1835,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]) } } @@ -1862,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]) } } @@ -1902,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 } } @@ -1935,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]) } } @@ -1950,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 } } } @@ -1984,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 } } } @@ -2015,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]) } } @@ -2031,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 } } } @@ -2062,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 @@ -2077,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 } } } @@ -2097,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]) } } @@ -2111,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 } } } @@ -2131,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) } @@ -2161,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]) } } @@ -2215,6 +2284,14 @@ class WasmArraySet: WasmOperation { } } +class WasmStructNew: WasmOperation { + override var opcode: Opcode { .wasmStructNew(self) } + + init(fieldCount: Int) { + super.init(numInputs: fieldCount + 1, numOutputs: 1, requiredContext: [.wasmFunction]) + } +} + class WasmStructNewDefault: WasmOperation { override var opcode: Opcode { .wasmStructNewDefault(self) } @@ -2266,10 +2343,20 @@ class WasmRefIsNull: WasmOperation { } } +class WasmRefEq: WasmOperation { + override var opcode: Opcode { .wasmRefEq(self) } + + init() { + super.init(numInputs: 2, numOutputs: 1, requiredContext: [.wasmFunction]) + } +} + class WasmRefI31: WasmOperation { override var opcode: Opcode { .wasmRefI31(self) } + let isShared: Bool - init() { + init(isShared: Bool) { + self.isShared = isShared super.init(numInputs: 1, numOutputs: 1, requiredContext: [.wasmFunction]) } } @@ -2300,6 +2387,29 @@ class WasmExternConvertAny: WasmOperation { } } +class WasmRefTest: WasmOperation { + override var opcode: Opcode { .wasmRefTest(self) } + let type: ILType + + init(refType: ILType) { + self.type = refType + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) + } +} + +class WasmRefCast: WasmOperation { + override var opcode: Opcode { .wasmRefCast(self) } + let type: ILType + init(refType: ILType) { + self.type = refType + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) + } +} + /// An atomic load from Wasm memory. /// The accessed address is base + offset. final class WasmAtomicLoad: WasmOperation { @@ -2313,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]) } } @@ -2330,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]) } } @@ -2343,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]) } } @@ -2388,6 +2501,38 @@ 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]) + } +} + +final class WasmDefineAdHocSignatureType: WasmOperation { + override var opcode: Opcode { .wasmDefineAdHocSignatureType(self) } + let signature: WasmSignature + + init(signature: WasmSignature) { + self.signature = signature + let numInputs = (signature.outputTypes + signature.parameterTypes).map { + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } + super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasmFunction]) + } +} + +// Same as WasmDefineAdHocSignatureType but not on the .wasmFunction context but .wasm (module). +// This is needed in cases where we aren't in the JS context any more but need a Wasm signature. +// TODO(mliedtke): We should explore alternative options. Right now this is a much better compromise +// than failing often to generate operations that require a signature, e.g. something simple like a +// Wasm function. +final class WasmDefineAdHocModuleSignatureType: WasmOperation { + override var opcode: Opcode { .wasmDefineAdHocModuleSignatureType(self) } + let signature: WasmSignature + + init(signature: WasmSignature) { + self.signature = signature + let numInputs = (signature.outputTypes + signature.parameterTypes).map { + $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 3a7f9f605..6ab97c135 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 } } } @@ -53,6 +53,9 @@ public class Fuzzer { /// The script runner used to execute generated scripts. public let runner: ScriptRunner + /// The script runners used to compare against in differential executions. + public let referenceRunner: ScriptRunner? + /// The fuzzer engine producing new programs from existing ones and executing them. public let engine: FuzzEngine @@ -84,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 { @@ -116,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 } @@ -126,6 +129,10 @@ public class Fuzzer { /// Start time of this fuzzing session private let startTime = Date() + public var isDifferentialFuzzing: Bool { + return referenceRunner != nil + } + /// Returns the uptime of this fuzzer as TimeInterval. public func uptime() -> TimeInterval { return -startTime.timeIntervalSinceNow @@ -160,14 +167,14 @@ public class Fuzzer { /// State management. private var iterations = 0 - private var iterationOfLastInteratingSample = 0 + private var iterationOfLastInterestingSample = 0 /// Currently active corpus import job, if any. private var currentCorpusImportJob = CorpusImportJob(corpus: [], mode: .full) private var iterationsSinceLastInterestingProgram: Int { - assert(iterations >= iterationOfLastInteratingSample) - return iterations - iterationOfLastInteratingSample + assert(iterations >= iterationOfLastInterestingSample) + return iterations - iterationOfLastInterestingSample } /// Fuzzer instances can be looked up from a dispatch queue through this key. See below. @@ -175,13 +182,17 @@ public class Fuzzer { /// Constructs a new fuzzer instance with the provided components. public init( - configuration: Configuration, scriptRunner: 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() @@ -196,10 +207,13 @@ public class Fuzzer { self.lifter = lifter self.corpus = corpus self.runner = scriptRunner + 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. if let postProcessor = engine.postProcessor { corpusGenerationEngine.registerPostProcessor(postProcessor) @@ -218,7 +232,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() @@ -226,7 +240,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() @@ -239,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 } @@ -251,7 +266,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. @@ -265,6 +280,9 @@ public class Fuzzer { // Initialize the script runner first so we are able to execute programs. runner.initialize(with: self) + if let referenceRunner { + referenceRunner.initialize(with: self) + } // Then initialize all components. engine.initialize(with: self) @@ -287,7 +305,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)." + ) } } @@ -301,13 +321,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" + ) } } } @@ -315,7 +339,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" + ) } } } @@ -403,7 +429,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) } @@ -424,11 +452,14 @@ public class Fuzzer { case imported case dropped case needsWasm + case needsBundles case failed(ExecutionOutcome) } 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. @@ -438,7 +469,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) { @@ -449,13 +482,19 @@ 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 } + if !config.generateBundle && program.code.isBundle { + return .needsBundles + } + let execution = execute(program, purpose: .programImport) var wasImported = false @@ -463,12 +502,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) 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 { @@ -494,10 +539,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)) } } @@ -534,7 +583,7 @@ public class Fuzzer { let dummy = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } var variablesToReplaceWithDummy = VariableSet() - b.adopting(from: program) { + b.adopting { for instr in program.code { var removeInstruction = false switch instr.op.opcode { @@ -548,7 +597,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) } @@ -570,17 +621,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, .needsBundles, .imported: + return (result, 0) + case .failed(_): + break } let b = makeBuilder() @@ -601,13 +654,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, .needsBundles, .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 { @@ -623,20 +675,21 @@ public class Fuzzer { } result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: - return (result, 2) - case .failed(_): - break + case .dropped, .needsWasm, .needsBundles, .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(from: program) { - 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) @@ -649,7 +702,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. @@ -690,7 +745,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) @@ -700,6 +757,13 @@ 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) + } + return execution } @@ -707,7 +771,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. @@ -720,11 +786,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 } @@ -736,7 +804,7 @@ public class Fuzzer { } while !didConverge || attempt < minAttempts if origin == .local { - iterationOfLastInteratingSample = iterations + iterationOfLastInterestingSample = iterations } // Determine whether the program needs to be minimized, then, using this helper function, dispatch the appropriate @@ -746,7 +814,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 })) @@ -764,7 +833,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) } @@ -772,30 +843,51 @@ 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 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) // 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)) @@ -809,7 +901,52 @@ 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 processCommon(_ program: Program) { + let hasDiffInfo = program.comments.at(.footer)?.contains("DIFFERENTIAL INFO") ?? false + if !hasDiffInfo { + let footerMessage = """ + DIFFERENTIAL INFO + ========== + STDERR: + \(stderr) + ARGS: \(runner.processArguments.joined(separator: " ")) + REFERENCE ARGS: \(referenceRunner!.processArguments.joined(separator: " ")) + """ + + program.comments.add(footerMessage, at: .footer) + } + + let execution = execute( + program, withTimeout: self.config.timeout * 2, + purpose: .checkForDeterministicBehavior) + if case .differential = execution.outcome { + dispatchEvent( + events.DifferentialFound, data: (program, .deterministic, true, origin)) + } else { + dispatchEvent(events.DifferentialFound, data: (program, .flaky, true, origin)) + } + } + + if !origin.requiresMinimization() { + return processCommon(program) + } + + fuzzGroup.enter() + minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { + minimizedProgram in self.fuzzGroup.leave() processCommon(minimizedProgram) } @@ -820,7 +957,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. @@ -862,34 +999,72 @@ 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)/" + ) } } + if !config.generateBundle { + logger.info( + "\(currentCorpusImportJob.numberOfProgramsRequiringBundlesButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require bundles which are disabled" + ) + } - 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 or bundles" + logger.warning( + "\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported." + ) } dispatchEvent(events.CorpusImportComplete) @@ -907,11 +1082,15 @@ 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?") + 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) } @@ -927,9 +1106,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]) @@ -945,33 +1122,40 @@ 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. /// 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) + 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?") + 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) 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("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 // 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) @@ -981,23 +1165,28 @@ 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 { - 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 @@ -1011,8 +1200,12 @@ 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") + 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) @@ -1020,10 +1213,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 @@ -1033,15 +1228,21 @@ 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) + 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!" { - 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 @@ -1052,8 +1253,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.") @@ -1063,6 +1266,53 @@ public class Fuzzer { return actualTimeout } + 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) + + let optimizedDump = try String(contentsOfFile: optPath, encoding: .utf8) + + if optimizedDump.isEmpty { + return execution + } + + // If we dumped at least one optimized frame, there is a point in unoptimized run. + let unoptExecution = referenceRunner!.run(script, withTimeout: timeout) + + // If unoptExecution didn't succeed just return the outcome, so that we can debug it. + // Comparison with relate tool is meaningless in such a case. + if unoptExecution.outcome != .succeeded { + return unoptExecution + } + + 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) + + if result.outcome == .differential { + logger.error( + """ + ================================================================ + [DUMPLING] POTENTIAL DIFFERENTIAL DETECTED + ================================================================ + """) + + logger.error(script) + } + + return result + + } catch { + fatalError("Critical failure: Unable to read dump files. Error: \(error)") + } + } + /// A pending corpus import job together with some statistics. private struct CorpusImportJob { private var corpusToImport: [Program] @@ -1082,14 +1332,17 @@ 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) - 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 } @@ -1122,9 +1375,11 @@ public class Fuzzer { break case .needsWasm: numberOfProgramsRequiringWasmButDisabled += 1 + case .needsBundles: + numberOfProgramsRequiringBundlesButDisabled += 1 case .failed(let outcome): switch outcome { - case .crashed, .succeeded: + case .crashed, .succeeded, .differential: // This is unexpected so we don't track these. break case .failed: 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 9a4e77785..dc7d7af68 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)) } @@ -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)'") @@ -73,16 +83,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))") @@ -108,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: @@ -133,6 +151,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 +169,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))") @@ -153,97 +189,86 @@ 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() + case .beginClassConstructor(let op): + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassConstructor\(inputs) -> \(params)") + w.increaseIndentionLevel() case .endClassConstructor: 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)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(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)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs.dropFirst()) + w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0))\(inputs) -> \(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,77 +278,47 @@ 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: + case .beginClassComputedGetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticComputedMethod \(input(0)) -> \(params)") + w.emit("BeginClassComputedGetter \(maybeStatic)\(input(0)) -> \(params)") w.increaseIndentionLevel() - case .endClassStaticComputedMethod: + case .endClassComputedGetter: w.decreaseIndentionLevel() - w.emit("EndClassStaticComputedMethod") + w.emit("EndClassComputedGetter") - case .beginClassStaticGetter(let op): + case .beginClassComputedSetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticGetter `\(op.propertyName)` -> \(params)") + w.emit("BeginClassComputedSetter \(maybeStatic)\(input(0)) -> \(params)") w.increaseIndentionLevel() - case .endClassStaticGetter: + case .endClassComputedSetter: w.decreaseIndentionLevel() - w.emit("EndClassStaticGetter") + w.emit("EndClassComputedSetter") - 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)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(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") + w.decreaseIndentionLevel() + w.emit("EndClassDefinition") case .createArray: let elems = instr.inputs.map(lift).joined(separator: ", ") @@ -367,7 +362,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" @@ -384,7 +381,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" @@ -397,11 +396,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))") @@ -416,27 +418,29 @@ 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)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("\(output()) <- \(op.name)\(inputs) -> \(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)") 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): @@ -468,35 +472,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 { @@ -522,19 +545,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))") @@ -607,28 +638,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))") @@ -717,7 +752,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: @@ -737,7 +774,7 @@ public class FuzzILLifter: Lifter { w.emit("EndRepeatLoop") case .loopBreak, - .switchBreak: + .switchBreak: w.emit("Break") case .loopContinue: @@ -780,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") @@ -792,14 +837,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 = "" @@ -807,7 +856,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") @@ -830,9 +881,11 @@ 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: @@ -848,7 +901,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 [...]") @@ -868,13 +923,15 @@ 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 [...]") - case .wasmDefineTag(let op): - w.emit("\(output()) <- WasmDefineTag \(op.parameterTypes)") + case .wasmDefineTag(_): + w.emit("\(output()) <- WasmDefineTag \(input(0))") case .wasmLoadGlobal(_): w.emit("\(output()) <- WasmLoadGlobal \(input(0))") @@ -892,22 +949,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))") @@ -988,25 +1057,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(_): @@ -1028,13 +1115,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 { @@ -1046,13 +1141,15 @@ public class FuzzILLifter: Lifter { case .wasmJsCall(let op): var arguments: [Variable] = [] - for i in 0.. 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): @@ -1097,9 +1196,11 @@ public class FuzzILLifter: Lifter { w.emit("WasmEndBlock \(inputs)") } - case .wasmBeginLoop(let op): + case .wasmBeginLoop(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginLoop (\(op.signature)) [\(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): @@ -1114,10 +1215,12 @@ public class FuzzILLifter: Lifter { case .wasmBeginTryTable(let op): let args = instr.inputs.map(lift) - let blockArgs = args.prefix(op.signature.parameterTypes.count).joined(separator: ", ") - w.emit("WasmBeginTryTable (\(op.signature)) [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + let blockArgs = args.prefix(1 + op.parameterCount).joined(separator: ", ") + w.emit( + "WasmBeginTryTable [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel(by: 2) - var inputIndex = op.signature.parameterTypes.count + 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])") @@ -1139,9 +1242,11 @@ public class FuzzILLifter: Lifter { w.emit("WasmEndTryTable \(inputs)") } - case .wasmBeginTry(let op): + case .wasmBeginTry(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginTry (\(op.signature)) [\(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(_): @@ -1154,7 +1259,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): @@ -1176,8 +1283,10 @@ public class FuzzILLifter: Lifter { case .wasmRethrow(_): w.emit("WasmRethrow \(instr.input(0))") - case .wasmBeginTryDelegate(let op): - w.emit("WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))] (\(op.signature))") + case .wasmBeginTryDelegate(_): + w.emit( + "WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndTryDelegate(_): @@ -1197,37 +1306,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)(\(op.signature)) [\(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: ", ") - // Note that the signature is printed by the WasmBeginIf, so we skip it here for better - // readability. - 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): @@ -1259,22 +1375,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))") @@ -1286,13 +1412,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: ", ") @@ -1312,6 +1444,10 @@ public class FuzzILLifter: Lifter { let inputs = instr.inputs.map(lift).joined(separator: ", ") w.emit("WasmArraySet [\(inputs)]") + case .wasmStructNew(_): + let inputs = instr.inputs.map(lift).joined(separator: ", ") + w.emit("\(output()) <- WasmStructNew [\(inputs)]") + case .wasmStructNewDefault(_): w.emit("\(output()) <- WasmStructNewDefault [\(input(0))]") @@ -1328,6 +1464,9 @@ public class FuzzILLifter: Lifter { case .wasmRefIsNull(_): w.emit("\(output()) <- WasmRefIsNull \(input(0))") + case .wasmRefEq(_): + w.emit("\(output()) <- WasmRefEq \(input(0)) \(input(1))") + case .wasmRefI31(_): w.emit("\(output()) <- WasmRefI31 \(input(0))") @@ -1340,6 +1479,14 @@ public class FuzzILLifter: Lifter { case .wasmExternConvertAny(_): w.emit("\(output()) <- WasmExternConvertAny \(input(0))") + case .wasmRefTest(let op): + let typeInput = op.type.requiredInputCount() > 0 ? " (IndexType: \(input(1)))" : "" + w.emit("\(output()) <- WasmRefTest \(op.type) \(input(0))\(typeInput)") + + case .wasmRefCast(let op): + let typeInput = op.type.requiredInputCount() > 0 ? " (IndexType: \(input(1)))" : "" + w.emit("\(output()) <- WasmRefCast \(op.type) \(input(0))\(typeInput)") + case .wasmBeginTypeGroup(_): w.emit("WasmBeginTypeGroup") w.increaseIndentionLevel() @@ -1354,12 +1501,23 @@ public class FuzzILLifter: Lifter { let inputs = instr.inputs.map(lift).joined(separator: ", ") w.emit("\(output()) <- WasmDefineSignatureType(\(op.signature)) [\(inputs)]") + case .wasmDefineAdHocSignatureType(let op): + let inputs = instr.inputs.map(lift).joined(separator: ", ") + w.emit("\(output()) <- WasmDefineAdHocSignatureType(\(op.signature)) [\(inputs)]") + + case .wasmDefineAdHocModuleSignatureType(let op): + let inputs = instr.inputs.map(lift).joined(separator: ", ") + w.emit("\(output()) <- WasmDefineAdHocModuleSignatureType(\(op.signature)) [\(inputs)]") + 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)]") @@ -1383,7 +1541,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) } @@ -1407,7 +1567,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] { @@ -1419,7 +1581,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 = "" @@ -1435,7 +1599,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 = "" @@ -1449,4 +1615,3 @@ public class FuzzILLifter: Lifter { return objectPattern } } - diff --git a/Sources/Fuzzilli/Lifting/JSExpressions.swift b/Sources/Fuzzilli/Lifting/JSExpressions.swift index 40a298a3d..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,24 +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, 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 1863c08b0..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) && isSimpleString(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); - 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); - 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); - 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 1cf8b75b9..858c62af5 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -34,7 +34,7 @@ public class JavaScriptLifter: Lifter { let version: ECMAScriptVersion /// This environment is used if we need to re-type a program before we compile Wasm code. - private var environment: JavaScriptEnvironment? + private var environment: JavaScriptEnvironment /// Counter to assist the lifter in detecting nested CodeStrings private var codeStringNestingLevel = 0 @@ -64,11 +64,24 @@ public class JavaScriptLifter: Lifter { } } - public init(prefix: String = "", - suffix: String = "", - ecmaVersion: ECMAScriptVersion, - environment: JavaScriptEnvironment? = nil, - alwaysEmitVariables: Bool = false) { + struct FunctionLiftingState { + let outputVariable: Variable + // If true, the function refers to itself (e.g. recursion), preventing inlining. + let isSelfReferencing: Bool + // For inlineable functions: + var parameters: String = "" + var isAsync: Bool = false + let startInstructionIndex: Int + } + private var functionLiftingStack = Stack() + + public init( + prefix: String = "", + suffix: String = "", + ecmaVersion: ECMAScriptVersion, + environment: JavaScriptEnvironment, + alwaysEmitVariables: Bool = false + ) { self.prefix = prefix self.suffix = suffix self.version = ecmaVersion @@ -77,6 +90,17 @@ public class JavaScriptLifter: Lifter { self.alwaysEmitVariables = alwaysEmitVariables } + 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 + } + } + public func lift(_ program: Program, withOptions options: LiftingOptions) -> String { liftedSamples += 1 // Perform some analysis on the program, for example to determine variable uses @@ -89,7 +113,21 @@ 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( + into: (indices: [Int: Int](), stack: Stack()) + ) { context, instr in + if instr.isBlockEnd { + let start = context.stack.pop() + context.indices[start] = instr.index + } + if instr.isBlockStart { + context.stack.push(instr.index) + } + }.indices + for instr in program.code { analyzer.analyze(instr) if instr.op is Explore { needToSupportExploration = true } @@ -101,10 +139,14 @@ 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(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 @@ -146,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) } @@ -191,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)) } @@ -210,7 +255,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: ", ") @@ -230,9 +277,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 { @@ -272,7 +320,8 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .loadString(let op): - w.assign(StringLiteral.new("\"\(op.value)\""), to: instr.output) + let escaped = op.value.replacingOccurrences(of: "\"", with: "\\\"") + w.assign(StringLiteral.new("\"\(escaped)\""), to: instr.output) case .loadRegExp(let op): let flags = op.flags.asString() @@ -324,20 +373,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. @@ -352,9 +401,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): @@ -377,8 +425,12 @@ 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 = op.methodName + 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)) @@ -387,7 +439,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)) @@ -397,20 +453,34 @@ 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)) + 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") 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)) + 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: @@ -418,14 +488,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) @@ -456,7 +528,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)) @@ -465,179 +541,137 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") - case .classAddInstanceProperty(let op): - let PROPERTY = op.propertyName + case .classAddProperty(let op): + let PROPERTY = quoteIdentifierIfNeeded(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 = op.methodName - w.emit("\(METHOD)(\(PARAMS)) {") + case .beginClassStaticInitializer: + w.emit("static {") 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 .endClassStaticInitializer: + w.leaveCurrentBlock() + w.emit("}") - case .beginClassInstanceGetter(let op): - let PROPERTY = op.propertyName - w.emit("get \(PROPERTY)() {") + case .beginClassMethod(let op): + let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") + 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)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassInstanceSetter(let op): - assert(instr.numInnerOutputs == 2) + case .beginClassComputedMethod(let op): 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)) {") + 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)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter: - 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 {") + case .beginClassGetter(let op): + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)get \(PROPERTY)() {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticMethod(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)) {") + 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 .beginClassStaticComputedMethod(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 METHOD = input(0) - w.emit("static [\(METHOD)](\(PARAMS)) {") + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)set \(PROPERTY)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticGetter(let op): - assert(instr.numInnerOutputs == 1) - let PROPERTY = op.propertyName - w.emit("static get \(PROPERTY)() {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput) - - case .beginClassStaticSetter(let op): - assert(instr.numInnerOutputs == 2) + case .beginClassComputedSetter(let op): 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 PROPERTY = input(0) + 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, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter: w.leaveCurrentBlock() w.emit("}") - case .classAddPrivateInstanceProperty(let op): + case .classAddPrivateProperty(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 .beginClassPrivateInstanceMethod(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("#\(METHOD)(\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .classAddPrivateStaticProperty(let op): - let PROPERTY = op.propertyName - if op.hasValue { - let VALUE = input(0) - w.emit("static #\(PROPERTY) = \(VALUE);") - } else { - w.emit("static #\(PROPERTY);") + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text } - - case .beginClassPrivateStaticMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) 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("}") @@ -647,7 +681,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 += "," @@ -673,8 +708,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 += "," } @@ -689,43 +724,47 @@ 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 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) 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): @@ -759,7 +798,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): @@ -793,7 +833,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: @@ -817,42 +858,75 @@ 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): - let LET = w.declarationKeyword(for: instr.output) - let V = w.declare(instr.output) - let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - w.emit("\(LET) \(V) = (\(PARAMS)) => {") - w.enterNewBlock() + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + 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): - let LET = w.declarationKeyword(for: instr.output) - let V = w.declare(instr.output) - let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - w.emit("\(LET) \(V) = async (\(PARAMS)) => {") - w.enterNewBlock() + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + 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: - w.leaveCurrentBlock() - w.emit("};") + .endAsyncArrowFunction: + let state = functionLiftingStack.pop() + if state.isSelfReferencing { + w.leaveCurrentBlock() + w.emit("};") + } else { + w.emitPendingExpressions() + let body = w.popTemporaryOutputBuffer() + + let trimmedBody = body.trimmingCharacters(in: .whitespacesAndNewlines) + var conciseBody: String? + + 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: ";"))) + conciseBody = content.hasPrefix("{") ? "(\(content))" : content + } + + let implementation = conciseBody ?? "{\n\(body)}" + let asyncPrefix = state.isAsync ? "async " : "" + let arrowFuncCode = "\(asyncPrefix)(\(state.parameters)) => \(implementation)" + + let expr = ArrowFunctionExpression.new(arrowFuncCode) + w.assign(expr, to: state.outputVariable) + } case .endPlainFunction(_), - .endGeneratorFunction(_), - .endAsyncFunction(_), - .endAsyncGeneratorFunction: + .endGeneratorFunction(_), + .endAsyncFunction(_), + .endAsyncGeneratorFunction: w.leaveCurrentBlock() w.emit("}") @@ -861,7 +935,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). @@ -912,7 +990,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: @@ -925,22 +1005,26 @@ 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) case .callMethod(let op): let obj = input(0) - let method = MemberExpression.new() + obj + "." + op.methodName + let method = MemberExpression.new() + obj + (liftMemberAccess(op.methodName)) let args = inputs.dropFirst() let expr = CallExpression.new() + method + "(" + liftCallArguments(args) + ")" w.assign(expr, to: instr.output) case .callMethodWithSpread(let op): let obj = input(0) - let method = MemberExpression.new() + obj + "." + op.methodName + 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: @@ -954,7 +1038,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): @@ -1010,7 +1096,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);") @@ -1018,13 +1105,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);") @@ -1032,7 +1121,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): @@ -1102,7 +1192,8 @@ public class JavaScriptLifter: Lifter { w.emit("\(EXPR);") case .callSuperMethod(let op): - let expr = CallExpression.new() + "super.\(op.methodName)(" + liftCallArguments(inputs) + ")" + let method = MemberExpression.new() + "super" + liftMemberAccess(op.methodName) + let expr = CallExpression.new() + method + "(" + liftCallArguments(inputs) + ")" w.assign(expr, to: instr.output) case .getPrivateProperty(let op): @@ -1132,13 +1223,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 + "]" @@ -1150,9 +1241,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) @@ -1251,7 +1342,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) @@ -1266,7 +1358,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() @@ -1275,7 +1368,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: @@ -1296,16 +1390,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) @@ -1335,7 +1432,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)) {") @@ -1362,7 +1460,7 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .loopBreak(_), - .switchBreak: + .switchBreak: w.emit("break;") case .loopContinue: @@ -1394,7 +1492,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) @@ -1405,7 +1503,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)`;") @@ -1417,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) @@ -1429,7 +1533,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) @@ -1445,7 +1551,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) @@ -1461,9 +1569,9 @@ public class JavaScriptLifter: Lifter { case .bindMethod(let op): let V = w.declare(instr.output) - let OBJECT = input(0) let LET = w.varKeyword - w.emit("\(LET) \(V) = Function.prototype.call.bind(\(OBJECT).\(op.methodName));") + let method = MemberExpression.new() + input(0) + liftMemberAccess(op.methodName) + w.emit("\(LET) \(V) = Function.prototype.call.bind(\(method));") case .bindFunction(_): let V = w.declare(instr.output) @@ -1478,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)) @@ -1486,7 +1594,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]) { @@ -1495,11 +1605,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 @@ -1792,7 +1931,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 @@ -1818,12 +1958,36 @@ public class JavaScriptLifter: Lifter { } } - private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { + func quoteIdentifierIfNeeded(_ name: String) -> String { + if environment.isValidIdentifierOrIndex(name) { + return name + } + return "\"\(name)\"" + } + + private func liftMemberAccess(_ name: String, isGuarded: Bool = false) -> String { + if environment.isValidDotNotationName(name) { + return (isGuarded ? "?." : ".") + name + } + let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" + return (isGuarded ? "?." : "") + "[" + safeName + "]" + } + + 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) } @@ -1831,7 +1995,10 @@ 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, 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). guard let op = instr.op as? BeginAnyFunction else { @@ -1845,12 +2012,66 @@ 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 liftCallArguments(_ args: Arguments, spreading spreads: [Bool] = []) -> String where Arguments.Element == Expression { + private func liftArrowFunctionDefinitionBegin( + _ instr: Instruction, + withInputs inputs: [Expression], + parameters: Parameters, + isAsync: Bool, + using w: inout JavaScriptWriter, + functionEndIndex: Int, + analyzer: DefUseAnalyzer + ) { + let isSelfReferencing = isUsedInBlock( + variable: instr.output, + blockStart: instr.index, + blockEnd: functionEndIndex, + analyzer: analyzer + ) + + let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") + + 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( + outputVariable: instr.output, + isSelfReferencing: isSelfReferencing, + parameters: params, + isAsync: isAsync, + startInstructionIndex: instr.index + )) + + if isSelfReferencing { + let keyword = w.declarationKeyword(for: instr.output) + let varName = w.declare(instr.output) + + w.emit("\(keyword) \(varName) = \(isAsync ? "async " : "")(\(params)) => {") + w.enterNewBlock() + } else { + w.emitPendingExpressions() + w.pushTemporaryOutputBuffer(initialIndentionLevel: 1) + } + } + + 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] { @@ -1863,7 +2084,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) { @@ -1891,7 +2114,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 = "" @@ -1907,7 +2132,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 = "" @@ -1937,13 +2164,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 @@ -1990,14 +2217,20 @@ public class JavaScriptLifter: Lifter { // List of effectful expressions that are still waiting to be inlined. In the order that they need to be executed at runtime. // The expressions are identified by the FuzzIL output variable that they generate. The actual expression is stored in the expressions dictionary. private var pendingExpressions = [Variable]() + private var pendingExpressionsStack = Stack<[Variable]>() // We also try to inline reassignments once, into the next use of the reassigned FuzzIL variable. However, for all subsequent uses we have to use the // identifier of the JavaScript variable again (the lhs of the reassignment). This map is used to remember these identifiers. // 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" @@ -2025,7 +2258,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) @@ -2076,7 +2311,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 @@ -2112,13 +2349,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 } } @@ -2204,7 +2444,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)) }) } @@ -2235,6 +2477,11 @@ public class JavaScriptLifter: Lifter { } mutating func emit(_ line: String) { + emitPendingExpressions() + writer.emitBlock(line) + } + + mutating func emitRaw(_ line: String) { emitPendingExpressions() writer.emit(line) } @@ -2261,13 +2508,18 @@ public class JavaScriptLifter: Lifter { mutating func pushTemporaryOutputBuffer(initialIndentionLevel: Int) { temporaryOutputBufferStack.push(writer) - writer = ScriptWriter(stripComments: writer.stripComments, includeLineNumbers: false, indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) + pendingExpressionsStack.push(pendingExpressions) + pendingExpressions = [] + writer = ScriptWriter( + stripComments: writer.stripComments, includeLineNumbers: false, + indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) } mutating func popTemporaryOutputBuffer() -> String { assert(pendingExpressions.isEmpty) let code = writer.code writer = temporaryOutputBufferStack.pop() + pendingExpressions = pendingExpressionsStack.pop() return code } @@ -2313,12 +2565,11 @@ public class JavaScriptLifter: Lifter { if EXPR.type === AssignmentExpression { // Reassignments require special handling: there is already a variable declared for the lhs, // so we only need to emit the AssignmentExpression as an expression statement. - writer.emit("\(EXPR);") + writer.emitBlock("\(EXPR);") } else if analyzer.numUses(of: v) > 0 { let LET = declarationKeyword(for: v) let V = declare(v) - // Need to use writer.emit instead of emit here as the latter will emit all pending expressions. - writer.emit("\(LET) \(V) = \(EXPR);") + writer.emitBlock("\(LET) \(V) = \(EXPR);") } else { // Pending expressions with no uses are allowed and are for example necessary to be able to // combine multiple expressions into a single comma-expression for e.g. a loop header. @@ -2328,9 +2579,9 @@ public class JavaScriptLifter: Lifter { // not be distinguishable from block statements. So create a dummy variable. let LET = constKeyword let V = declare(v) - writer.emit("\(LET) \(V) = \(EXPR);") + writer.emitBlock("\(LET) \(V) = \(EXPR);") } else { - writer.emit("\(EXPR);") + writer.emitBlock("\(EXPR);") } } } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift index 071c4d8c5..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 (!isSimpleString(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 6f9882ad8..9b2448dbb 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -15,579 +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 "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 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 (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. - 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 = EmptyArray()) { - 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 = EmptyArray()) { - 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) || !isSimpleString(name)) throw "SpecialInput name is not a (simple) 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) || !isSimpleString(value)) throw "StringInput value is not a (simple) 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..ec84c02b3 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 @@ -54,12 +57,12 @@ 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) 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 +74,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 +97,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 287d1cc5e..e9e35cc1c 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 @@ -258,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 { @@ -290,21 +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 freeTypes: 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] = [] @@ -343,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. @@ -375,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 @@ -386,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)) } } @@ -403,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? { @@ -470,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))") } } @@ -528,33 +528,26 @@ public class WasmLifter { self.bytecode += [0x1, 0x0, 0x0, 0x0] } - private func encodeAbstractHeapType(_ heapType: WasmAbstractHeapType) -> Data { - switch (heapType) { - case .WasmExtern: - return Data([0x6F]) - case .WasmFunc: - return Data([0x70]) - case .WasmAny: - return Data([0x6E]) - case .WasmEq: - return Data([0x6D]) - case .WasmI31: - return Data([0x6C]) - case .WasmStruct: - return Data([0x6B]) - case .WasmArray: - return Data([0x6A]) - case .WasmExn: - return Data([0x69]) - case .WasmNone: - return Data([0x71]) - case .WasmNoExtern: - return Data([0x72]) - case .WasmNoFunc: - return Data([0x73]) - case .WasmNoExn: - return Data([0x74]) - } + private func encodeAbstractHeapType(_ heapTypeInfo: HeapTypeInfo) -> Data { + // Base of v8 implementation. See + // 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 + } + return Data(sharedFlagPrefix + [opCode]) } private func encodeWasmGCType(_ description: WasmTypeDescription?) throws -> Data { @@ -569,28 +562,39 @@ public class WasmLifter { let isNullable = refType.nullability let nullabilityByte: UInt8 = isNullable ? 0x63 : 0x64 - switch refType.kind { - case .Index(let description): - return try Data([nullabilityByte]) + encodeWasmGCType(description.get()) - case .Abstract(let heapType): - return Data([nullabilityByte]) + encodeAbstractHeapType(heapType) - } + return try Data([nullabilityByte]) + encodeHeapType(refType.kind) } // HINT: If you crash here, you might not have specified an encoding for your new type in `ILTypeMapping`. return ILTypeMapping[type] ?? ILTypeMapping[defaultType!]! } - private func encodeHeapType(_ type: ILType, defaultType: ILType? = nil) throws -> Data { + private func encodeHeapType(_ refKind: WasmReferenceType.Kind) throws -> Data { + switch refKind { + case .Index(let description): + return try encodeWasmGCType(description.get()) + case .Abstract(let heapTypeInfo): + return encodeAbstractHeapType(heapTypeInfo) + } + } + + // Convienience method to avoid casting to wasmReferenceType on callers side. + private func encodeHeapType(_ type: ILType) throws -> Data { if let refType = type.wasmReferenceType { - switch refType.kind { - case .Index(let description): - return try encodeWasmGCType(description.get()) - case .Abstract(let heapType): - return encodeAbstractHeapType(heapType) - } + return try encodeHeapType(refType.kind) + } + fatalError("This function supports only wasmReferenceType.") + } + + // 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 { + switch refType.kind { + case .Abstract(let heapTypeInfo): + return encodeAbstractHeapType(heapTypeInfo) + case .Index(_): + return try encodeWasmGCType(typer.getTypeDescription(of: instr.input(typeInput))) } - // HINT: If you crash here, you might not have specified an encoding for your new type in `ILTypeMapping`. - return ILTypeMapping[type] ?? ILTypeMapping[defaultType!]! } private func buildTypeEntry(for desc: WasmTypeDescription, data: inout Data) throws { @@ -621,29 +625,24 @@ 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 }) { registerSignature(signature) } - // Special handling for defined Tags - for case let .tag(instr) in self.exports { - let tagSignature = (instr!.op as! WasmDefineTag).parameterTypes => [] - assert(tagSignature.outputTypes.isEmpty) - registerSignature(tagSignature) - } // Special handling for defined functions - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { registerSignature(functionInfo!.signature) } 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. @@ -655,7 +654,6 @@ public class WasmLifter { try buildTypeEntry(for: typer.getTypeDescription(of: typeDef), data: &temp) } } - // TODO(mliedtke): Also add "free types" which aren't in any explicit type group. for signature in self.signatures { temp += [0x60] @@ -665,7 +663,7 @@ public class WasmLifter { } temp += Leb128.unsignedEncode(signature.outputTypes.count) for outputType in signature.outputTypes { - temp += try encodeType(outputType, defaultType: .wasmExternRef) + temp += try encodeType(outputType, defaultType: .wasmExternRef()) } } @@ -716,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)! @@ -744,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)) @@ -760,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)) @@ -777,7 +780,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 } @@ -797,13 +800,18 @@ 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 { + for case .function(let functionInfo) in self.exports { temp.append(Leb128.unsignedEncode(try getSignatureIndex(functionInfo!.signature))) } @@ -820,11 +828,16 @@ 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 { + for case .table(let instruction) in self.exports { let op = instruction!.op as! WasmDefineTable let elementType = op.elementType let minSize = op.limits.min @@ -860,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 { @@ -892,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) @@ -928,15 +941,19 @@ 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]() 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 } @@ -956,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) @@ -976,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 @@ -992,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) @@ -1012,6 +1034,10 @@ public class WasmLifter { } private func buildDataSection() throws { + if self.dataSegments.isEmpty { + return + } + self.bytecode += [WasmSection.data.rawValue] var temp = Data() @@ -1019,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) } @@ -1036,11 +1062,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) @@ -1053,14 +1080,16 @@ 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 { + for case .global(let instruction) in self.exports { let definition = instruction!.op as! WasmDefineGlobal let global = definition.wasmGlobal @@ -1079,16 +1108,16 @@ public class WasmLifter { case .wasmi64(let val): temporaryInstruction = Instruction(Consti64(value: val), output: Variable()) case .externref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef) + Data([0x0B]) + temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef()) + Data([0x0B]) continue case .exnref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef) + Data([0x0B]) + temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef()) + Data([0x0B]) continue case .i31ref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref) + Data([0x0B]) + temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref()) + Data([0x0B]) continue case .refFunc(_), - .imported(_): + .imported(_): fatalError("unreachable") } temp += try lift(temporaryInstruction!) @@ -1108,20 +1137,21 @@ 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 { + 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)) @@ -1143,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) @@ -1151,10 +1181,10 @@ public class WasmLifter { section += Leb128.unsignedEncode(self.exports.count { $0.isTag }) - for case let .tag(instr) in self.exports { - let tagSignature = (instr!.op as! WasmDefineTag).parameterTypes => [] + for case .tag(let instr) in self.exports { + let signatureDesc = typer.getTypeDescription(of: instr!.input(0)) section.append(0) - section.append(Leb128.unsignedEncode(try getSignatureIndex(tagSignature))) + section.append(Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) } self.bytecode.append(Leb128.unsignedEncode(section.count)) @@ -1170,6 +1200,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() @@ -1184,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) }) @@ -1234,54 +1269,63 @@ public class WasmLifter { } } - /// This function updates the internal state of the lifter before actually emitting code to the wasm module. This should be invoked before we try to get the corresponding bytes for the Instruction + /// This function updates the internal state of the lifter before actually emitting code to the + /// wasm module. This should be invoked before we try to get the corresponding bytes for the + /// Instruction. + /// Returns true if the instruction requires emitting code into the module's code section (which + /// means it is true for almost all instructions appearing inside a wasm function and false for + /// all instructions outside of a wasm function like a Wasm memory definition). private func updateLifterState(wasmInstruction instr: Instruction) -> Bool { // Make sure that we actually have a Wasm operation here. assert(instr.op is WasmOperation) switch instr.op.opcode { - case .wasmBeginBlock(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginBlock(_): + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginIf(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginIf(_): + 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(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginTryTable(_): + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginTry(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginTry(_): + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginTryDelegate(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginTryDelegate(_): + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginLoop(let op): - registerSignature(op.signature) - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + case .wasmBeginLoop(_): + 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): @@ -1294,27 +1338,33 @@ 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 - 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(_): @@ -1324,16 +1374,20 @@ 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: return true } @@ -1343,8 +1397,10 @@ public class WasmLifter { // requires that the instr has been analyzed before. Maybe assert that? private func emitInputLoadsIfNecessary(forInstruction instr: Instruction) { - // Don't emit loads for reassigns. This is specially handled in the `lift` function for reassigns. - if instr.op is WasmReassign { + // Don't emit loads for reassigns. This is specially handled in the `lift` function for + // reassigns. WasmDefineAdHocSignatureType isn't a wasm instruction and therefore also + // doesn't have any Wasm stack inputs. + if instr.op is WasmReassign || instr.op is WasmDefineAdHocSignatureType { return } @@ -1352,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 } @@ -1376,20 +1432,27 @@ public class WasmLifter { } private func emitStackSpillsIfNecessary(forInstruction instr: Instruction) { - // Don't emit spills for reassigns. This is specially handled in the `lift` function for reassigns. - // Similarly, the end of a function doesn't spill anything. - if instr.op is WasmReassign || instr.op is EndWasmFunction { + // Don't emit spills for reassigns. This is specially handled in the `lift` function for + // 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 + { 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(.anyWasmLabel) }) 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)) } } @@ -1397,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) } } @@ -1434,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. @@ -1453,15 +1515,15 @@ public class WasmLifter { for (idx, input) in instr.inputs.enumerated() { let inputType = typer.type(of: input) - if inputType.Is(.wasmTypeDef()) || inputType.Is(.wasmRef(.Index(), nullability: true)) { + if inputType.Is(.wasmTypeDef()) || inputType.Is(.anyIndexRef) { let typeDesc = typer.getTypeDescription(of: input) - if typeDesc.typeGroupIndex != -1 { - // Add typegroups and their dependencies. - if typeGroups.insert(typeDesc.typeGroupIndex).inserted { - typeGroups.formUnion(typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) - } - } else { - freeTypes.insert(input) + guard typeDesc.typeGroupIndex != -1 else { + throw CompileError.fatalError("Missing type group index for \(input)") + } + // Add typegroups and their dependencies. + if typeGroups.insert(typeDesc.typeGroupIndex).inserted { + typeGroups.formUnion( + typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) } } @@ -1479,18 +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 case .wasmJsCall(let op) = instr.op.opcode { - importIfNeeded(.import(type: .function(nil), variable: input, signature: op.functionSignature)) + 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) + ) } 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. @@ -1505,11 +1577,15 @@ public class WasmLifter { self.exports.append(.global(instr)) case .wasmDefineTable(let tableDef): self.exports.append(.table(instr)) - if tableDef.elementType == .wasmFuncRef { + // TODO(pawkra): support shared refs. + if tableDef.elementType == .wasmFuncRef() { 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)) } } } @@ -1573,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 @@ -1597,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. @@ -1610,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) @@ -1805,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)) @@ -1866,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) @@ -1883,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) - case .wasmJsCall(let op): + 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 = op.functionSignature + 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. @@ -1901,62 +1997,76 @@ public class WasmLifter { return false } }).firstIndex(where: { - wasmInstruction.input(0) == $0.getImport()!.variable && wasmSignature == $0.getImport()!.signature + wasmInstruction.input(1) == $0.getImport()!.variable + && wasmSignature == $0.getImport()!.signature }) { return Data([0x10]) + Leb128.unsignedEncode(index) } else { throw WasmLifter.CompileError.failedIndexLookUp } - case .wasmBeginBlock(let op): + case .wasmBeginBlock(_): // A Block can "produce" (push) an item on the value stack, just like a function. Similarly, a block can also have parameters. // Ref: https://webassembly.github.io/spec/core/binary/instructions.html#binary-blocktype - return Data([0x02] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) - case .wasmBeginLoop(let op): - return Data([0x03] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + return Data([0x02] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) + case .wasmBeginLoop(_): + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + return Data([0x03] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) case .wasmBeginTryTable(let op): - var inputIndex = op.signature.parameterTypes.count + 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(signatureIndexMap[op.signature]!) + + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!) + Leb128.unsignedEncode(op.catches.count) + catchTable - case .wasmBeginTry(let op): - return Data([0x06] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) - case .wasmBeginTryDelegate(let op): - return Data([0x06] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) + case .wasmBeginTry(_): + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + return Data([0x06] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) + case .wasmBeginTryDelegate(_): + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + return Data([0x06] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) case .wasmBeginCatchAll(_): return Data([0x19]) case .wasmBeginCatch(_): - return Data([0x07] + Leb128.unsignedEncode(try resolveIdx(ofType: .tag, for: wasmInstruction.input(0)))) + 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(_): - let branchDepth = try branchDepthFor(label: wasmInstruction.input(0)) + let branchDepth = try branchDepthFor(label: wasmInstruction.input(1)) // Mutation might make this EndTryDelegate branch to itself, which should not happen. if branchDepth < 0 { throw WasmLifter.CompileError.invalidBranch } 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(_): @@ -1964,19 +2074,23 @@ 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) + Data(op.labelTypes.map {_ in 0x1A}) + 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) + Data(op.labelTypes.map {_ in 0x1A}) + 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 beginIf = Data([0x04] + Leb128.unsignedEncode(try getSignatureIndex(op.signature))) + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + let beginIf = Data([0x04] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) // Invert the condition with an `i32.eqz` (resulting in 0 becoming 1 and everything else becoming 0). return op.inverted ? Data([0x45]) + beginIf : beginIf case .wasmBeginElse(_): @@ -1986,7 +2100,7 @@ public class WasmLifter { // wasmReassign is quite special, it needs to work for variables stored in various places, e.g. local slots or even globals. As such the lifting here first needs to locate the destination variable. var out = Data() - var storeInstruction = Data() + let storeInstruction: Data // If the variable is a local, we load the stack slot. // Check for the stack location of the `to` variable. if let stackSlot = currentFunction!.getStackSlot(for: wasmInstruction.input(0)) { @@ -1996,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. @@ -2006,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 @@ -2019,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) @@ -2078,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) @@ -2087,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]) @@ -2145,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]!) @@ -2160,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 @@ -2168,13 +2332,19 @@ public class WasmLifter { let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) let arrayIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) return Data([Prefix.GC.rawValue, 0x0E]) + arrayIndex + case .wasmStructNew(_): + let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + let structIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) + return Data([Prefix.GC.rawValue, 0x00]) + structIndex case .wasmStructNewDefault(_): let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) 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 @@ -2187,8 +2357,10 @@ public class WasmLifter { return try Data([0xD0]) + encodeHeapType(typer.type(of: wasmInstruction.output)) case .wasmRefIsNull(_): return Data([0xD1]) - case .wasmRefI31(_): - return Data([Prefix.GC.rawValue, 0x1C]) + case .wasmRefEq(_): + return Data([0xD3]) + case .wasmRefI31(let op): + return Data([Prefix.GC.rawValue, op.isShared ? 0x1F : 0x1C]) case .wasmI31Get(let op): let opCode: UInt8 = op.isSigned ? 0x1D : 0x1E return Data([Prefix.GC.rawValue, opCode]) @@ -2196,9 +2368,23 @@ public class WasmLifter { return Data([Prefix.GC.rawValue, 0x1A]) case .wasmExternConvertAny(_): return Data([Prefix.GC.rawValue, 0x1B]) + case .wasmRefTest(let op): + let refType = op.type.wasmReferenceType! + let opCode: UInt8 = refType.nullability ? 0x15 : 0x14 + let typeData = try encodeReferenceType(refType, instr: wasmInstruction, typeInput: 1) + return Data([Prefix.GC.rawValue, opCode]) + typeData + case .wasmRefCast(let op): + let refType = op.type.wasmReferenceType! + let opCode: UInt8 = refType.nullability ? 0x17 : 0x16 + let typeData = try encodeReferenceType(refType, instr: wasmInstruction, typeInput: 1) + return Data([Prefix.GC.rawValue, opCode]) + typeData + case .wasmDefineAdHocSignatureType(_): + // Nothing to do here, types are defined inside the typegroups, not inside a wasm + // function. + return Data() default: - fatalError("unreachable") + fatalError("unreachable") } } } diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 5a1efac08..1de029dcc 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -27,9 +27,11 @@ struct BlockReducer: Reducer { reduceObjectLiteral(group.block(0), with: helper) case .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralSetter: + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter: assert(group.numBlocks == 1) reduceFunctionInObjectLiteral(group.block(0), with: helper) @@ -37,26 +39,22 @@ struct BlockReducer: Reducer { reduceClassDefinition(group.block(0), with: helper) case .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, - .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .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: @@ -69,41 +67,42 @@ 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, + .beginBundleScript: 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: @@ -211,7 +210,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) @@ -226,7 +226,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) @@ -258,7 +258,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) { @@ -334,17 +340,21 @@ struct BlockReducer: Reducer { let beginInstr = helper.code[group.head] let endInstr = helper.code[group.tail] + // Drop the signature from the inputs before remapping. + let blockInputs = beginInstr.inputs.dropFirst() + let endInstrInputs = endInstr.inputs.dropFirst() var varReplacements = Dictionary( - uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), beginInstr.inputs)) - varReplacements.merge(zip(endInstr.outputs, endInstr.inputs.map {varReplacements[$0] ?? $0}), - uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) - var newCode = Code() + uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), blockInputs)) + varReplacements.merge( + zip(endInstr.outputs, endInstrInputs.map { varReplacements[$0] ?? $0 }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) + 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. + 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) @@ -374,7 +384,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) @@ -422,7 +434,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) @@ -445,14 +459,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} - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() if helper.testAndCommit(newCode) { @@ -533,22 +557,29 @@ 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)) + 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.map {varReplacements[$0] ?? $0}), uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) - var newCode = Code() + varReplacements.merge( + zip( + helper.code[elseBlock.tail].outputs, + helper.code[elseBlock.tail].inputs.dropFirst().map { + varReplacements[$0] ?? $0 + }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) + 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. + 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) { @@ -560,7 +591,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) @@ -592,7 +625,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..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 { @@ -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 { @@ -79,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 { @@ -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 be6bed5d6..f6af53318 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -44,58 +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, - .beginObjectLiteralSetter, - .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, - .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .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, - .endObjectLiteralSetter, - .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, - .endClassStaticInitializer, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .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)) @@ -118,10 +114,17 @@ struct InliningReducer: Reducer { // Can't inline functions that are passed as arguments to other functions. deleteCandidates(instr.inputs.dropFirst()) + case .loadDisposableVariable, + .createNamedDisposableVariable, + .loadAsyncDisposableVariable, + .createNamedAsyncDisposableVariable: + // Can't inline functions that are also used as a disposable variable. + deleteCandidates(instr.inputs) + fallthrough case .loadNewTarget, - .loadArguments, - .loadDisposableVariable: + .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! { candidates.removeValue(forKey: function) } @@ -133,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. @@ -142,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. @@ -255,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/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 6c6c60d5b..cc4c8b79a 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) 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)) } } } @@ -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)) } } } @@ -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)) } } } @@ -116,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 @@ -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): @@ -143,10 +160,16 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, idx) in op.indices.enumerated() { - if i == op.indices.last! && op.lastIsRest { - newCode.append(Instruction(DestructArray(indices: [idx], lastIsRest: true), output: outputs.last!, inputs: [instr.input(0)])) + if i == op.indices.count - 1 && op.lastIsRest { + 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..6acce260b 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,38 +98,50 @@ 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!] : [])) // 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)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } 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)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } 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)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } // 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) } 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) } 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()) + #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. @@ -144,7 +154,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) // 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) @@ -187,18 +207,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 +240,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 +266,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 +288,8 @@ 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) } } diff --git a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift index 6254e0971..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 { @@ -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..e759f9eb3 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.isStaticallyValid()) + assert( + helper.code.countIntructionsWith(flags: .notRemovable) + >= helper.numKeptInstructions) + helper.code.assertIsStaticallyValid() } 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 @@ -124,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 c6a290d08..c69cb0128 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 { @@ -82,11 +82,11 @@ 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)) } } - assert(newCode.isStaticallyValid()) + newCode.assertIsStaticallyValid() if didChangeCode { helper.testAndCommit(newCode) } 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 96d6d4870..aeeaf7b37 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -12,43 +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 + } } - // For now, we only consider EndTypeGroup instructions. - guard case .wasmEndTypeGroup = instr.op.opcode else { continue } - - candidates.append(instr.index) - 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 + } } } - // Remove those candidates whose outputs are all used. - candidates = candidates.filter {helper.code[$0].allOutputs.map({ uses[$0]! }).contains {$0 == 0}} - - if candidates.isEmpty { + if definitions.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)) + // 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 } + + 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]!) + } + + let newInouts = keptInoutsMap.map { $0.0 } + keptInoutsMap.map { $0.1 } + endTypeGroupReplacements[instr.index] = Instruction( + WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts) + } + + if toRemove.isEmpty { + return } - helper.tryReplacements(replacements, renumberVariables: true) + + var newCode = Code( + helper.code + .filter { !toRemove.contains($0.index) } + .map { endTypeGroupReplacements[$0.index] ?? $0 }, isBundle: helper.code.isBundle) + + newCode.renumberVariables() + helper.testAndCommit(newCode) } } 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 @@ -214,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)" + ) } } @@ -238,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 9c9860d57..9d3d08afa 100644 --- a/Sources/Fuzzilli/Modules/Storage.swift +++ b/Sources/Fuzzilli/Modules/Storage.swift @@ -19,12 +19,15 @@ public class Storage: Module { private let storageDir: String private let crashesDir: String private let duplicateCrashesDir: String + private let differentialsDir: String private let corpusDir: String private let statisticsDir: String private let stateFile: String private let failedDir: String private let timeOutDir: String private let diagnosticsDir: String + private let optimizedDumpDir: String + private let unoptimizedDumpDir: String private let statisticsExportInterval: Double? @@ -35,12 +38,15 @@ public class Storage: Module { self.storageDir = storageDir self.crashesDir = storageDir + "/crashes" self.duplicateCrashesDir = storageDir + "/crashes/duplicates" + self.differentialsDir = storageDir + "/differentials" self.corpusDir = storageDir + "/corpus" self.failedDir = storageDir + "/failed" self.timeOutDir = storageDir + "/timeouts" self.statisticsDir = storageDir + "/stats" self.stateFile = storageDir + "/state.bin" self.diagnosticsDir = storageDir + "/diagnostics" + self.optimizedDumpDir = storageDir + "/optimizedDump" + self.unoptimizedDumpDir = storageDir + "/unoptimizedDump" self.statisticsExportInterval = statisticsExportInterval @@ -50,17 +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: 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) } } 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 { @@ -69,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() @@ -83,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 @@ -95,6 +120,11 @@ public class Storage: Module { } } + fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { ev in + let filename = "program_\(self.formatDate())_\(ev.program.id)_\(ev.behaviour.rawValue)" + self.storeProgram(ev.program, as: filename, in: self.differentialsDir) + } + fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { ev in let filename = "program_\(self.formatDate())_\(ev.program.id)" self.storeProgram(ev.program, as: filename, in: self.corpusDir) @@ -124,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) + } } } @@ -193,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..e45507e61 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. @@ -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 { @@ -161,7 +162,18 @@ 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)!" + ) + } + + 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) @@ -191,7 +203,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 +220,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 +270,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 +295,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 +338,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 +357,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 +378,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 +455,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 +476,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 +496,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 +507,8 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { } case .crashingProgram, - .statistics, - .log: + .statistics, + .log: logger.error("Received unexpected message: \(messageType)") } } @@ -508,6 +545,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 d769dd0de..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(from: program) { + 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 34450e8fc..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(from: program) { + 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(from: instrumentedProgram) { + 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 957a59f14..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,17 +336,28 @@ 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 + // inconsistent program (we essentially dropped a random instruction that e.g. + // may have produced an output variable used later on). + // This is mostly unexpected (so we log an error), but can legitimately happen + // during V8 sandbox fuzzing as we will randomly corrupt heap memory there. logger.error("Failed to process action: \(msg)") + return (nil, .unexpectedError) } catch { logger.error("Unexpected error during action processing \(error)") + // Same as above, we need to abort the mutation here. + return (nil, .unexpectedError) } 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) @@ -305,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 01398b3ac..1fdcee1ed 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,11 +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]) - replacement = b.randomVariable(ofType: type) + // 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) } else { switch self.typeAwareness { case .loose: @@ -78,13 +84,14 @@ 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. // 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/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 dfe3438df..8f24ce7d3 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 { @@ -44,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()) @@ -55,19 +65,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 { @@ -748,7 +860,9 @@ public class OperationMutator: BaseInstructionMutator { return instr } - private func extendVariadicOperationByOneInput(_ instr: Instruction, _ b: ProgramBuilder) -> 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 } @@ -770,28 +884,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) @@ -824,10 +945,12 @@ 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(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 d3173eb65..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(from: program) { + 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(from: instrumentedProgram) { + 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,25 +204,30 @@ 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 { 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) @@ -223,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)) @@ -257,14 +275,14 @@ 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) 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) } } @@ -279,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 { @@ -297,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 @@ -312,11 +336,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 +351,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/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index a99c33f21..6dbf6e2c0 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" @@ -59,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 @@ -79,7 +85,58 @@ public class RuntimeAssistedMutator: Mutator { // May be overwritten by child classes } - override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + // 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, expectedSignal: Int + ) + -> Program? + { + let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) + 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( + 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) + 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 back to FuzzIL: \(error)") + return nil + } + } + + 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) @@ -89,7 +146,13 @@ 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 + 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,15 +172,61 @@ 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.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) + } + } + + // 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, expectedSignal: signal) + ?? instrumentedProgram + fuzzer.processCrash( + programToReport, withSignal: signal, + withStderr: oldStderr, withStdout: stdout, origin: .local, + withExectime: execution.execTime) case .succeeded: // The expected case. break + case .differential: + fatalError("Differential result impossible") } // 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) @@ -132,7 +241,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() @@ -230,11 +341,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): @@ -243,7 +358,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) @@ -256,17 +372,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. @@ -275,7 +400,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. @@ -386,7 +514,7 @@ extension RuntimeAssistedMutator.Action { case .BitwiseXor: try translateBinaryOperation(.Xor) case .NullCoalesce: - try translateBinaryOperation(.NullCoalesce) + try translateBinaryOperation(.NullCoalesce) case .LeftShift: try translateBinaryOperation(.LShift) case .SignedRightShift: 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/FuzzilliCli/Profiles/DuktapeProfile.swift b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift similarity index 71% rename from Sources/FuzzilliCli/Profiles/DuktapeProfile.swift rename to Sources/Fuzzilli/Profiles/DuktapeProfile.swift index 001ce27a8..b22ddef87 100644 --- a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift +++ b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - let duktapeProfile = Profile( processArgs: { randomize in ["--reprl"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, @@ -26,10 +26,10 @@ let duktapeProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -51,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/FuzzilliCli/Profiles/JSCProfile.swift b/Sources/Fuzzilli/Profiles/JSCProfile.swift similarity index 71% rename from Sources/FuzzilliCli/Profiles/JSCProfile.swift rename to Sources/Fuzzilli/Profiles/JSCProfile.swift index d79b85360..85b906036 100644 --- a/Sources/FuzzilliCli/Profiles/JSCProfile.swift +++ b/Sources/Fuzzilli/Profiles/JSCProfile.swift @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - -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) @@ -23,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) @@ -32,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")) } @@ -50,7 +52,8 @@ let jscProfile = Profile( "--thresholdForFTLOptimizeSoon=1000", // Enable bounds check elimination validation "--validateBCE=true", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -69,18 +72,20 @@ let jscProfile = Profile( return args }, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processArgsReference: nil, + + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -99,7 +104,7 @@ let jscProfile = Profile( additionalCodeGenerators: [ (ForceDFGCompilationGenerator, 5), (ForceFTLCompilationGenerator, 5), - (GcGenerator, 5), + (GcGenerator, 5), ], additionalProgramTemplates: WeightedList([]), @@ -109,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/FuzzilliCli/Profiles/JerryscriptProfile.swift b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift similarity index 80% rename from Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift rename to Sources/Fuzzilli/Profiles/JerryscriptProfile.swift index acc18406d..65f160296 100644 --- a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift +++ b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift @@ -12,24 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - let jerryscriptProfile = Profile( processArgs: { randomize in ["--reprl-fuzzilli"] }, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processArgsReference: nil, + + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -51,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/FuzzilliCli/Profiles/NjsProfile.swift b/Sources/Fuzzilli/Profiles/NjsProfile.swift similarity index 96% rename from Sources/FuzzilliCli/Profiles/NjsProfile.swift rename to Sources/Fuzzilli/Profiles/NjsProfile.swift index 040ef711d..42b01cd29 100644 --- a/Sources/FuzzilliCli/Profiles/NjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/NjsProfile.swift @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - let njsProfile = Profile( processArgs: { randomize in ["fuzz"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, @@ -26,10 +26,10 @@ let njsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, diff --git a/Sources/FuzzilliCli/Profiles/Profile.swift b/Sources/Fuzzilli/Profiles/Profile.swift similarity index 53% rename from Sources/FuzzilliCli/Profiles/Profile.swift rename to Sources/Fuzzilli/Profiles/Profile.swift index 0947d9559..b8d0fc063 100644 --- a/Sources/FuzzilliCli/Profiles/Profile.swift +++ b/Sources/Fuzzilli/Profiles/Profile.swift @@ -12,42 +12,47 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - -struct Profile { - let processArgs: (_ randomize: Bool) -> [String] - let processEnv: [String : String] - let maxExecsBeforeRespawn: Int +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 maxExecsBeforeRespawn: Int // Timeout either by value or interval in milliseconds. - let timeout: Timeout - let codePrefix: String - let codeSuffix: String - let ecmaVersion: ECMAScriptVersion + public let timeout: Timeout + public let codePrefix: String + public let codeSuffix: String + public let ecmaVersion: ECMAScriptVersion // JavaScript code snippets that are executed at startup time to ensure that Fuzzilli and the target engine are configured correctly. - let startupTests: [(String, ExpectedStartupTestResult)] + public let startupTests: [(String, ExpectedStartupTestResult)] - let additionalCodeGenerators: [(CodeGenerator, Int)] - let additionalProgramTemplates: WeightedList + public let additionalCodeGenerators: [(CodeGenerator, Int)] + public let additionalProgramTemplates: WeightedList - let disabledCodeGenerators: [String] - let disabledMutators: [String] + public let disabledCodeGenerators: [String] + public let disabledMutators: [String] - let additionalBuiltins: [String: ILType] - let additionalObjectGroups: [ObjectGroup] - let additionalEnumerations: [ILType] + public let additionalBuiltins: [String: ILType] + public let additionalObjectGroups: [ObjectGroup] + public let additionalEnumerations: [ILType] // An optional post-processor that is executed for every sample generated for fuzzing and can modify it. - let optionalPostProcessor: FuzzingPostProcessor? + public let optionalPostProcessor: FuzzingPostProcessor? + + public var isDifferential: Bool { + return processArgsReference != nil + } } -let profiles = [ +public let profiles = [ "qtjs": qtjsProfile, "qjs": qjsProfile, "jsc": jscProfile, "spidermonkey": spidermonkeyProfile, "v8": v8Profile, "v8Sandbox": v8SandboxProfile, + "v8Dumpling": v8DumplingProfile, "duktape": duktapeProfile, "jerryscript": jerryscriptProfile, "xs": xsProfile, diff --git a/Sources/FuzzilliCli/Profiles/QjsProfile.swift b/Sources/Fuzzilli/Profiles/QjsProfile.swift similarity index 92% rename from Sources/FuzzilliCli/Profiles/QjsProfile.swift rename to Sources/Fuzzilli/Profiles/QjsProfile.swift index aa521f001..5a344b4f5 100644 --- a/Sources/FuzzilliCli/Profiles/QjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QjsProfile.swift @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - let qjsProfile = Profile( processArgs: { randomize in ["--reprl"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, @@ -26,10 +26,10 @@ let qjsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -52,7 +52,7 @@ let qjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "placeholder" : .function([] => .undefined) + "placeholder": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift b/Sources/Fuzzilli/Profiles/QtjsProfile.swift similarity index 81% rename from Sources/FuzzilliCli/Profiles/QtjsProfile.swift rename to Sources/Fuzzilli/Profiles/QtjsProfile.swift index c536f529b..fddd2a071 100644 --- a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QtjsProfile.swift @@ -11,13 +11,14 @@ // 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 Fuzzilli // 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) } } @@ -27,17 +28,19 @@ let qtjsProfile = Profile( ["-reprl"] }, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processArgsReference: nil, + + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -50,7 +53,7 @@ let qtjsProfile = Profile( ], additionalCodeGenerators: [ - (ForceQV4JITGenerator, 20), + (ForceQV4JITGenerator, 20) ], additionalProgramTemplates: WeightedList([]), @@ -60,7 +63,7 @@ let qtjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), + "gc": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/FuzzilliCli/Profiles/Serenity.swift b/Sources/Fuzzilli/Profiles/Serenity.swift similarity index 90% rename from Sources/FuzzilliCli/Profiles/Serenity.swift rename to Sources/Fuzzilli/Profiles/Serenity.swift index 496e833b9..134cb875a 100644 --- a/Sources/FuzzilliCli/Profiles/Serenity.swift +++ b/Sources/Fuzzilli/Profiles/Serenity.swift @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - let serenityProfile = Profile( processArgs: { randomize in return [""] }, + processArgsReference: nil, processEnv: [ "UBSAN_OPTIONS": "handle_segv=0 handle_abrt=0", "ASAN_OPTIONS": "abort_on_error=1", @@ -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/FuzzilliCli/Profiles/SpidermonkeyProfile.swift b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift similarity index 84% rename from Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift rename to Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift index ec131d243..4e4a1110b 100644 --- a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift +++ b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - -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) @@ -23,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")) } @@ -36,7 +36,8 @@ let spidermonkeyProfile = Profile( "--ion-extra-checks", "--fuzzing-safe", "--disable-oom-functions", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -61,15 +62,20 @@ 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 }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, @@ -77,11 +83,11 @@ let spidermonkeyProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -99,7 +105,7 @@ let spidermonkeyProfile = Profile( additionalCodeGenerators: [ (ForceSpidermonkeyIonGenerator, 10), - (GcGenerator, 10), + (GcGenerator, 10), ], additionalProgramTemplates: WeightedList([]), @@ -109,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/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift similarity index 56% rename from Sources/FuzzilliCli/Profiles/V8CommonProfile.swift rename to Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 4c83c2b31..68478c62f 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -12,29 +12,69 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli +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"]) + 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 let fastCallables : [(group: ILType, method: String)] = [ +extension ObjectGroup { + public static let jsWorkers = ObjectGroup( + name: "Worker", + instanceType: .jsWorker, + properties: [:], + methods: [ + "postMessage": [.jsAnything] => .undefined, + "getMessage": [] => .jsAnything, + "terminate": [] => .undefined, + "terminateAndWait": [] => .undefined, + ] + ) + + public static let jsWorkerPrototype = + ObjectGroup.createPrototypeObjectGroup(jsWorkers, constructor: .jsWorkerConstructor) + + public static let jsWorkerConstructors = ObjectGroup( + name: "WorkerConstructor", + constructorPath: "Worker", + instanceType: .jsWorkerConstructor, + properties: [ + "prototype": jsWorkerPrototype.instanceType + ], + methods: [:] + ) +} + +public let fastCallables: [(group: ILType, method: String)] = [ (group: .jsD8FastCAPI, method: "throw_no_fallback"), (group: .jsD8FastCAPI, method: "add_32bit_int"), ] @@ -48,10 +88,28 @@ 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)]) +} + +public let V8MajorGcGenerator = CodeGenerator("MajorGcGenerator") { b in + // Differently to `gc()`, this intrinsic is registered with less effects, preventing fewer + // optimizations in V8's optimizing compilers. + 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) @@ -60,39 +118,87 @@ public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITComp } } -public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in - assert(b.type(of: f).Is(.function())) - let arguments = b.randomArguments(forCalling: f) - - b.callFunction(f, withArgs: arguments) - - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - - b.callFunction(f, withArgs: arguments) - b.callFunction(f, withArgs: arguments) - - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); +// 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] +) { + var reusePool: [[Variable]] = [b.randomArguments(forCalling: f)] + let reuseProbabilities = [1.0, 0.9, 0.9, 0.5] + + let argumentLists = reuseProbabilities.map { p in + if probability(p) { + return reusePool.randomElement()! + } else { + reusePool.append(b.randomArguments(forCalling: f)) + return reusePool.last! + } + } - b.callFunction(f, withArgs: arguments) + assert(argumentLists.count == 4) + return (argumentLists[0], argumentLists[1], argumentLists[2], argumentLists[3]) } -public let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in - assert(b.type(of: f).Is(.function())) - let arguments = b.randomArguments(forCalling: f) +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) - b.callFunction(f, withArgs: arguments) + let guardCalls = probability(0.5) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.callFunction(f, withArgs: args1, guard: guardCalls) - b.callFunction(f, withArgs: arguments) - b.callFunction(f, withArgs: arguments) + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]) - b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); + b.callFunction(f, withArgs: args2, guard: guardCalls) + b.callFunction(f, withArgs: args3, guard: guardCalls) - b.callFunction(f, withArgs: arguments) + b.eval("%\(optimizeName)(%@)", with: [f]) + + b.callFunction(f, withArgs: args4, guard: guardCalls) + } } -public let TurbofanVerifyTypeGenerator = CodeGenerator("TurbofanVerifyTypeGenerator", inputs: .one) { b, v in +public let ForceTurboFanCompilationGenerator = forceCompilationGenerator( + "ForceTurboFanCompilationGenerator", optimizeName: "OptimizeFunctionOnNextCall") + +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() @@ -356,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 @@ -392,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(resultVar, to: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: 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(resultVar, to: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: 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(resultVar, to: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: 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) } @@ -464,24 +648,25 @@ 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 // stack frames this should trigger a lazy deoptimization. - b.eval("%DeoptimizeNow();"); + b.eval("%DeoptimizeNow();") b.build(n: 30) b.doReturn(b.randomJsVariable()) } // Turn the call into a recursive call. - b.reassign(dummyFct, to: realFct) + b.reassign(variable: dummyFct, value: realFct) let args = b.randomArguments(forCalling: realFct) - b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); - b.callFunction(realFct, withArgs: args) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]); + let guardCalls = probability(0.5) + b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]) + b.callFunction(realFct, withArgs: args, guard: guardCalls) + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]) // Call the function. - b.callFunction(realFct, withArgs: args) + b.callFunction(realFct, withArgs: args, guard: guardCalls) } public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in @@ -493,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) } @@ -513,16 +699,20 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in } let table = wasmModule.addTable( - elementType: .wasmFuncRef, + 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 @@ -596,17 +791,22 @@ 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.error("Arguments should have been generated") + Logger(withLabel: "V8CommonProfile").error("Arguments should have been generated") } return wasmSignature.outputTypes.map(fbuilder.findOrGenerateWasmVar) } @@ -631,26 +831,111 @@ 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) } let args = b.randomJsVariables(n: Int.random(in: 0...5)) - b.callFunction(f, withArgs: args) + 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.callFunction(f, withArgs: args) - b.callFunction(f, withArgs: args) + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); + b.callFunction(f, withArgs: args, guard: guardCalls) + + b.build(n: 10) +} - b.callFunction(f, withArgs: args) +public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") { b in + b.buildPrefix() + 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 + 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) + } + } + ) + // Explicitly expose the prototype property to make modifications of it more likely. + b.getProperty("prototype", of: fct) + // Allow further modifications on the function. + b.build(n: 10) + // Perform the prototype assignments. + for _ in 0.. [String] { "--omit-quit", "--allow-natives-syntax", "--fuzzing", - "--jit-fuzzing", "--future", "--harmony", "--experimental-fuzzing", @@ -669,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") @@ -687,6 +971,11 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { if probability(0.5) { args.append("--maglev-as-top-tier") } + } else if probability(0.1) { + args.append( + probability(0.5) + ? "--turbo-instruction-scheduling" + : "--turbo-stress-instruction-scheduling") } if probability(0.1) { @@ -701,6 +990,10 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--no-short-builtin-calls") } + if probability(0.8) { + args.append("--jit-fuzzing") + } + // Disabling Liftoff enables "direct" coverage for the optimizing compiler, though some // features (like speculative inlining) require a combination of Liftoff and Turbofan. // Note that this flag only affects WebAssembly. @@ -719,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. // @@ -734,6 +1032,12 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } if !args.contains("--no-maglev") { + if probability(0.5) { + args.append("--maglev-untagged-phis") + } + if probability(0.1) { + args.append("--no-maglev-loop-peeling") + } if probability(0.25) { args.append("--maglev-future") } @@ -745,7 +1049,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") } } @@ -755,20 +1059,16 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--turboshaft-typed-optimizations") } - if probability(0.5) { + if probability(0.7) { 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") } } } - if probability(0.1) { - args.append("--turboshaft-wasm-in-js-inlining") - } - if probability(0.1) { args.append("--harmony-struct") } @@ -803,19 +1103,26 @@ 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") } if probability(0.5) { - args.append("--proto-assign-seq-opt") + args.append("--proto-assign-seq-lazy-func-opt") + if probability(0.5) { + args.append("--proto-assign-seq-opt-count=1") + } + } + + if probability(0.5) { + args.append("--private-field-bytecodes") } // @@ -834,6 +1141,10 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { if probability(0.1) { 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 + args.append("--maglev-assert-types") + } if probability(0.1) { args.append("--turboshaft-assert-types") } @@ -843,10 +1154,15 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { if probability(0.1) { args.append("--turboshaft-verify-reductions") } + if probability(0.2) { + args.append("--turboshaft-verify-load-store-taggedness") + } } 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") @@ -877,17 +1193,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"])) } } @@ -911,11 +1231,12 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { chooseBooleanFlag("always-osr") chooseBooleanFlag("concurrent-osr") chooseBooleanFlag("force-slow-path") + chooseBooleanFlag("lazy") + chooseBooleanFlag("lazy-eval") // Maglev related flags chooseBooleanFlag("maglev-inline-api-calls") chooseBooleanFlag("maglev-inlining") - chooseBooleanFlag("maglev-loop-peeling") chooseBooleanFlag("maglev-optimistic-peeled-loops") chooseBooleanFlag("maglev-pretenure-store-values") chooseBooleanFlag("maglev-poly-calls") @@ -924,11 +1245,10 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { chooseBooleanFlag("maglev-range-analysis") chooseBooleanFlag("maglev-escape-analysis") chooseBooleanFlag("maglev-licm") - chooseBooleanFlag("maglev-untagged-phis") // 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") @@ -943,7 +1263,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") @@ -961,7 +1285,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { chooseBooleanFlag("wasm-bulkmem-inlining") chooseBooleanFlag("wasm-lazy-compilation") chooseBooleanFlag("wasm-lazy-validation") - chooseBooleanFlag("wasm-simd-ssse3-codegen") } return args diff --git a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift new file mode 100644 index 000000000..8c404a79f --- /dev/null +++ b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift @@ -0,0 +1,187 @@ +// 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. + +let v8DumplingProfile = Profile( + processArgs: { randomize in + var args = [ + "--expose-gc", + "--expose-externalize-string", + "--omit-quit", + "--allow-natives-syntax", + "--fuzzing", + "--jit-fuzzing", + "--future", + "--harmony", + "--experimental-fuzzing", + "--js-staging", + "--expose-fast-api", + "--predictable", + "--no-sparkplug", + "--maglev-dumping", + "--turbofan-dumping", + ] + + return args + }, + + // TODO(mdanylo): currently we run Fuzzilli in differential fuzzing + // mode if processArgsReference is not nil. We should reconsider + // this decision in the future in favour of something nicer. + processArgsReference: [ + "--sparkplug-dumping", + "--interpreter-dumping", + "--no-maglev", + "--no-turbofan", + "--expose-gc", + "--expose-externalize-string", + "--omit-quit", + "--allow-natives-syntax", + "--fuzzing", + "--jit-fuzzing", + "--future", + "--harmony", + "--experimental-fuzzing", + "--js-staging", + "--expose-fast-api", + "--predictable", + ], + + processEnv: [:], + + maxExecsBeforeRespawn: 1000, + + 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 --- + """, + + codeSuffix: """ + """, + + ecmaVersion: ECMAScriptVersion.es6, + + startupTests: [ + + ], + + additionalCodeGenerators: [ + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), + + (V8GcGenerator, 10), + ], + + additionalProgramTemplates: WeightedList([ + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), + ]), + + disabledCodeGenerators: [], + + disabledMutators: [], + + additionalBuiltins: [ + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .jsD8, + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), + ], + + additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], + + additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], + + optionalPostProcessor: DumplingFuzzingPostProcessor() +) + +/// A post-processor for the Dumpling profile. +/// +/// Work-around for differential fuzzing to avoid f.arguments. +/// Or any access to "arguments" with a computed property. We just +/// overapproximate this by checking for any string occurence of +/// "arguments" and reject the sample. +public struct DumplingFuzzingPostProcessor: FuzzingPostProcessor { + public func process(_ program: Program, for fuzzer: Fuzzer) throws -> Program { + for instr in program.code { + switch instr.op.opcode { + case .loadString(let op) where op.value == "arguments": + throw InternalError.postProcessRejection("\"arguments\" string") + case .getProperty(let op) where op.propertyName == "arguments": + throw InternalError.postProcessRejection("f.arguments access") + case .setProperty(let op) where op.propertyName == "arguments": + throw InternalError.postProcessRejection("f.arguments assignment") + case .updateProperty(let op) where op.propertyName == "arguments": + throw InternalError.postProcessRejection("f.arguments update") + case .deleteProperty(let op) where op.propertyName == "arguments": + throw InternalError.postProcessRejection("f.arguments deletion") + default: + break + } + } + + return program + } +} diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift similarity index 72% rename from Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift rename to Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift index c7c72aa09..a3985adbb 100644 --- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - // 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) } @@ -36,6 +34,8 @@ let v8HoleFuzzingProfile = Profile( return args }, + processArgsReference: nil, + processEnv: [:], maxExecsBeforeRespawn: 1000, @@ -43,10 +43,10 @@ let v8HoleFuzzingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -67,24 +67,25 @@ let v8HoleFuzzingProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 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/FuzzilliCli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift similarity index 50% rename from Sources/FuzzilliCli/Profiles/V8Profile.swift rename to Sources/Fuzzilli/Profiles/V8Profile.swift index b239caf55..3ffb35672 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli - -let v8Profile = Profile( - processArgs: {randomize in - v8ProcessArgs(randomize: randomize, forSandbox: false) +public let v8Profile = Profile( + processArgs: { randomize in + v8ProcessArgs(randomize: randomize, forSandbox: false) }, + processArgsReference: nil, + // We typically fuzz without any sanitizer instrumentation, but if any sanitizers are active, "abort_on_error=1" must probably be set so that sanitizer errors can be detected. processEnv: [:], @@ -27,10 +27,10 @@ let v8Profile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -49,34 +49,45 @@ let v8Profile = Profile( ("fuzzilli('FUZZILLI_CRASH', 3)", .shouldCrash), // Check that DEBUG is defined. ("fuzzilli('FUZZILLI_CRASH', 8)", .shouldCrash), + // Check that abort_with_sandbox_violation works. + ("fuzzilli('FUZZILLI_CRASH', 9)", .shouldCrash), // TODO we could try to check that OOM crashes are ignored here ( with.shouldNotCrash). ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), - - (WorkerGenerator, 10), - (V8GcGenerator, 10), - - (WasmStructGenerator, 15), - (WasmArrayGenerator, 15), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 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), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (WasmFastCallFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), + (WasmDeoptFuzzer, 1), + (WasmTurbofanFuzzer, 1), + (ProtoAssignSeqOptFuzzer, 1), + (TurbofanTierUpNonInlinedCallFuzzer, 1), ]), disabledCodeGenerators: [], @@ -84,12 +95,20 @@ let v8Profile = 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": .jsWorkerConstructor, + // via --expose-externalize-string: + "externalizeString": .function([.plain(.jsString)] => .jsString), + "isOneByteString": .function([.plain(.jsString)] => .boolean), + "createExternalizableString": .function([.plain(.jsString)] => .jsString), + "createExternalizableTwoByteString": .function([.plain(.jsString)] => .jsString), ], - additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], + 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 new file mode 100644 index 000000000..7f4c4f0ef --- /dev/null +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -0,0 +1,587 @@ +// Copyright 2023 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. + +// A post-processor that inserts calls to the sandbox corruption functions (defined in the codeSuffix below) into the generated samples. +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 + // generated program might hamper that. + if probability(0.5) { return program } + + let b = fuzzer.makeBuilder(forMutating: program) + + enum TraversalStep: Int { + case neighbor = 0 + case pointer = 1 + } + + 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 } + let numCorruptions = Int.random(in: 1...3) + for _ in 0.. String in + if probability(0.25) { + let hashQuery = Int.random(in: 0...0xffff) + return "[\(TraversalStep.neighbor.rawValue), \(hashQuery)]" + } else { + let offsetSeed = UInt32.random(in: 0...UInt32.max) + return "[\(TraversalStep.pointer.rawValue), \(offsetSeed)]" + } + }.joined(separator: ", ") + let pathArray = "[\(pathTuples)]" + + let size = chooseUniform(from: [8, 16, 32]) + let offsetSeed = UInt32.random(in: 0...UInt32.max) + + let subFieldOffset = + switch size { + case 8: Int.random(in: 0..<4) + case 16: Int.random(in: 0..<2) * 2 + default: 0 + } + + let command: String + switch Double.random(in: 0..<1) { + case 0.80..<0.90: + let bitPosition = Int.random(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", + ], + + maxExecsBeforeRespawn: 1000, + + // ASan builds are slower, so we use a larger timeout. + timeout: Timeout.interval(500, 1200), + + codePrefix: """ + // + // 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. + + function getSandboxCorruptionHelpers() { + // In general, memory contents are represented as (unsigned) BigInts, everything else (addresses, offsets, etc.) are Numbers. + + function assert(c) { + if (!c) { + throw new Error("Assertion in the in-sandbox-corruption API failed!"); + } + } + + 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)); + } + } + + 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; + } + } + + 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); + } + 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; + + 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; + } + } + + return currentWinner; + } + + // 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 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; + } + } + + function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return null; + + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return null; + + 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))); + + 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; + } + + 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; + } + } + } + return Sandbox.isWritableObjectAt(addr) ? addr : null; + } + + return { + builtins, getBaseAddress, evaluateTraversalPath, prepareDataCorruptionContext + }; + } + + function corruptDataWithBitflip(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { + 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"); + } + + 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; + + 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; + + let newValue = oldValue ^ (1n << BigInt(bitPosition)); + + 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)); + } + + 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, + + startupTests: [ + // This makes sure that the fuzzilli builtin exists. + ("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed), + // This makes sure that the memory corruption api is available. + ("Sandbox.getAddressOf([1, 2, 3])", .shouldSucceed), + // This makes sure that the corruption functions are available and working. It should not corrupt anything as it's passed an object in read-only space ('undefined'). + // TODO: Adding tests that stress the pathArray traversal logic could be beneficial. + ("corruptDataWithBitflip(undefined, [], 0, 8, 0, 0);", .shouldSucceed), + ("corruptDataWithIncrement(42, [], 0, 8, 0, 0n);", .shouldSucceed), + ("corruptDataWithReplace('test', [], 0, 8, 0, 0n);", .shouldSucceed), + ("corruptWithWorker(Symbol('test'), [], 0, 8, 0, 0);", .shouldSucceed), + // We cannot pass a real function here because `Sandbox.setFunctionCodeToBuiltin` will abort the process if the chosen builtin's parameter count doesn't match the target function. + ("corruptFunction(undefined, [], 0);", .shouldSucceed), + // This triggers a DCHECK failure, which should be ignored, and execution should continue. + ("fuzzilli('FUZZILLI_CRASH', 2)", .shouldSucceed), + // This checks that we do not have DEBUG defined, and execution should continue. + ("fuzzilli('FUZZILLI_CRASH', 8)", .shouldSucceed), + + // Crashes that indicate a sandbox violation should be detected. + // This should crash with a wild write. + ("fuzzilli('FUZZILLI_CRASH', 3)", .shouldCrash), + // This should crash with an ASan-detectable use-after-free. + ("fuzzilli('FUZZILLI_CRASH', 4)", .shouldCrash), + // This should crash with an ASan-detectable out-of-bounds write. + ("fuzzilli('FUZZILLI_CRASH', 6)", .shouldCrash), + // This should crash due to calling abort_with_sandbox_violation(). + ("fuzzilli('FUZZILLI_CRASH', 9)", .shouldCrash), + // This should crash due to executing an invalid machine code instruction. + ("fuzzilli('FUZZILLI_CRASH', 11)", .shouldCrash), + + // Crashes that are not sandbox violations and so should be filtered out by the crash filter. + // This triggers an IMMEDIATE_CRASH. + ("fuzzilli('FUZZILLI_CRASH', 0)", .shouldNotCrash), + // This triggers a CHECK failure. + ("fuzzilli('FUZZILLI_CRASH', 1)", .shouldNotCrash), + // This triggers a std::vector OOB access that should be caught by the libc++ hardening. + ("fuzzilli('FUZZILLI_CRASH', 5)", .shouldNotCrash), + // This triggers a `ud 2` which might for example be used for release asserts and so should be ignored. + ("fuzzilli('FUZZILLI_CRASH', 10)", .shouldNotCrash), + ], + + 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), + ], + + additionalProgramTemplates: WeightedList([ + (BytecodeFuzzer, 2) + ]), + + disabledCodeGenerators: [], + + disabledMutators: [], + + additionalBuiltins: [ + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .object(), + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), + ], + + additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], + + additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], + + optionalPostProcessor: SandboxFuzzingPostProcessor() +) diff --git a/Sources/Fuzzilli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift new file mode 100644 index 000000000..c7407040d --- /dev/null +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -0,0 +1,391 @@ +// Copyright 2019-2024 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. + +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.callFunction(f, withArgs: arguments) + b.unary(.PostInc, index) + let result = b.callFunction(gc, withArgs: [index]) + b.buildIf(result) { + b.loopBreak() + } + } +} + +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(1_000_000) + let memoryFail = b.createNamedVariable(forBuiltin: "memoryFail") + 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.callFunction(f, withArgs: arguments) + b.unary(.PostInc, index) + b.callFunction(memoryFail, withArgs: [index]) + } +} + +private let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { + b, obj in + let harden = b.createNamedVariable(forBuiltin: "harden") + + if probability(0.05) { + let lockdown = b.createNamedVariable(forBuiltin: "lockdown") + b.callFunction(lockdown) + } + b.callFunction(harden, withArgs: [obj]) +} + +private let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in + let moduleSourceConstructor = b.createNamedVariable(forBuiltin: "ModuleSource") + + let code = b.buildCodeString { + b.build(n: 5) + } + + b.construct(moduleSourceConstructor, withArgs: [code]) +} + +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 moduleMap = [String: Variable]() + var options = [String: Variable]() + + for _ in 0.. '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", + ] + + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in + let (pattern, flags) = b.randomRegExpPatternAndFlags() + let regExpVar = b.loadRegExp(pattern, flags) + + let lastIndex = chooseUniform(from: lastIndices) + let lastIndexString = b.loadString(lastIndex) + + b.setProperty("lastIndex", of: regExpVar, to: lastIndexString) + + let subjectVar: Variable + + if probability(0.1) { + subjectVar = b.loadString(twoByteSubjectString) + } else { + subjectVar = b.loadString(b.randomString()) + } + + 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) + }) + }, + catchBody: { _ in + }) + + b.build(n: 7) + + b.doReturn(resultVar) + } + + b.callFunction(f) + + b.build(n: 15) +} + +extension ILType { + /// Type of a JavaScript Compartment object. + public static let jsCompartment = ILType.object( + ofGroup: "Compartment", withProperties: ["globalThis"], + withMethods: ["evaluate", "import", "importNow" /* , "module" */]) + + public static let jsCompartmentConstructor = + ILType.constructor([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartment) + + .object(ofGroup: "CompartmentConstructor", withProperties: ["prototype"], withMethods: []) + + public static let jsModuleSource = ILType.object( + ofGroup: "ModuleSource", withProperties: ["bindings", "needsImport", "needsImportMeta"]) + + public static let jsModuleSourceConstructor = + ILType.constructor([.opt(.string)] => .jsModuleSource) + + .object( + ofGroup: "ModuleSourceConstructor", withProperties: ["prototype"], withMethods: []) +} + +/// Object group modelling JavaScript compartments. +let jsCompartments = ObjectGroup( + name: "Compartment", + instanceType: .jsCompartment, + properties: [ + "globalThis": .object() + ], + methods: [ //@@ import/importNow can accept more than strings + "import": [.string] => .jsPromise, + "importNow": [.string] => .jsAnything, + // "module" : [.opt(.string)] => .object(), (currently unavailable) + "evaluate": [.string] => .jsAnything, + ] +) + +let jsCompartmentConstructor = ObjectGroup( + name: "CompartmentConstructor", + instanceType: .jsCompartmentConstructor, + properties: [ + "prototype": .object() + ], + methods: [:] +) + +/// Object group modelling JavaScript ModuleSources. +let jsModuleSources = ObjectGroup( + name: "ModuleSource", + instanceType: .jsModuleSource, + properties: [ + "bindings": .object(), + "needsImport": .object(), + "needsImportMeta": .object(), + ], + methods: [:] +) + +let jsModuleSourceConstructor = ObjectGroup( + name: "ModuleSourceConstructor", + instanceType: .jsModuleSourceConstructor, + properties: [ + "prototype": .object() + ], + methods: [:] +) + +let xsProfile = Profile( + processArgs: { randomize in + ["-f"] + }, + + 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", + ], + + maxExecsBeforeRespawn: 1000, + + timeout: Timeout.value(250), + + codePrefix: """ + """, + + codeSuffix: """ + gc(); + """, + + ecmaVersion: ECMAScriptVersion.es6, + + startupTests: [ + // Check that the fuzzilli integration is available. + ("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed), + + // Check that common crash types are detected. + ("fuzzilli('FUZZILLI_CRASH', 0)", .shouldCrash), + ("fuzzilli('FUZZILLI_CRASH', 1)", .shouldCrash), + ("fuzzilli('FUZZILLI_CRASH', 2)", .shouldCrash), + ], + + additionalCodeGenerators: [ + (StressXSMemoryFail, 5), + (StressXSGC, 5), + (HardenGenerator, 5), + (CompartmentGenerator, 5), + (CompartmentEvaluateGenerator, 5), + (UnicodeStringGenerator, 2), + (ModuleSourceGenerator, 3), + ], + + additionalProgramTemplates: WeightedList([ + (RegExpFuzzer, 1) + ]), + + disabledCodeGenerators: [], + + disabledMutators: [], + + additionalBuiltins: [ + "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()), + ], + + additionalObjectGroups: [ + jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor, + ], + + additionalEnumerations: [], + + optionalPostProcessor: nil +) 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..(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2463,20 +2493,25 @@ extension Compiler_Protobuf_AST: SwiftProtobuf.Message, SwiftProtobuf._MessageIm // 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.statements) }() + case 1: try { try decoder.decodeSingularStringField(value: &self.leadingComments) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.statements) }() default: break } } } public func traverse(visitor: inout V) throws { + if !self.leadingComments.isEmpty { + try visitor.visitSingularStringField(value: self.leadingComments, fieldNumber: 1) + } if !self.statements.isEmpty { - try visitor.visitRepeatedMessageField(value: self.statements, fieldNumber: 1) + try visitor.visitRepeatedMessageField(value: self.statements, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_AST, rhs: Compiler_Protobuf_AST) -> Bool { + if lhs.leadingComments != rhs.leadingComments {return false} if lhs.statements != rhs.statements {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -2485,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 } @@ -2709,9 +2791,9 @@ extension Compiler_Protobuf_DisposableVariableDeclaration: SwiftProtobuf.Message } } -extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".FunctionDeclaration" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}type\0\u{1}parameters\0\u{1}body\0") +extension Compiler_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}parameters\0\u{1}hasRestElement\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2719,44 +2801,34 @@ extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftPro // 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 2: try { try decoder.decodeSingularEnumField(value: &self.type) }() - case 3: try { try decoder.decodeRepeatedMessageField(value: &self.parameters) }() - case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.parameters) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } - if self.type != .plain { - try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) - } if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 3) + try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 1) } - if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) + if self.hasRestElement_p != false { + try visitor.visitSingularBoolField(value: self.hasRestElement_p, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Compiler_Protobuf_FunctionDeclaration, rhs: Compiler_Protobuf_FunctionDeclaration) -> Bool { - if lhs.name != rhs.name {return false} - if lhs.type != rhs.type {return false} + public static func ==(lhs: Compiler_Protobuf_Parameters, rhs: Compiler_Protobuf_Parameters) -> Bool { if lhs.parameters != rhs.parameters {return false} - if lhs.body != rhs.body {return false} + if lhs.hasRestElement_p != rhs.hasRestElement_p {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Compiler_Protobuf_PropertyKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".PropertyKey" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}index\0\u{1}expression\0") +extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".FunctionDeclaration" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\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() { @@ -2764,7 +2836,56 @@ extension Compiler_Protobuf_PropertyKey: 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 { + case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + 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 + } + } + } + + 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.name.isEmpty { + try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) + } + if self.type != .plain { + try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) + } + try { if let v = self._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + if !self.body.isEmpty { + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Compiler_Protobuf_FunctionDeclaration, rhs: Compiler_Protobuf_FunctionDeclaration) -> Bool { + if lhs.name != rhs.name {return false} + if lhs.type != rhs.type {return false} + if lhs._parameters != rhs._parameters {return false} + if lhs.body != rhs.body {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Compiler_Protobuf_PropertyKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".PropertyKey" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}index\0\u{1}expression\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 { var v: String? try decoder.decodeSingularStringField(value: &v) if let v = v { @@ -2882,7 +3003,7 @@ extension Compiler_Protobuf_ClassConstructor: SwiftProtobuf.Message, SwiftProtob // 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.parameters) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() case 2: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } @@ -2890,9 +3011,13 @@ extension Compiler_Protobuf_ClassConstructor: SwiftProtobuf.Message, SwiftProtob } public func traverse(visitor: inout V) throws { - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, 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._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if !self.body.isEmpty { try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 2) } @@ -2900,7 +3025,7 @@ extension Compiler_Protobuf_ClassConstructor: SwiftProtobuf.Message, SwiftProtob } public static func ==(lhs: Compiler_Protobuf_ClassConstructor, rhs: Compiler_Protobuf_ClassConstructor) -> Bool { - if lhs.parameters != rhs.parameters {return false} + if lhs._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -2919,7 +3044,7 @@ extension Compiler_Protobuf_ClassMethod: SwiftProtobuf.Message, SwiftProtobuf._M switch fieldNumber { 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.parameters) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } @@ -2937,9 +3062,9 @@ extension Compiler_Protobuf_ClassMethod: SwiftProtobuf.Message, SwiftProtobuf._M if self.isStatic != false { try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) } - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 3) - } + try { if let v = self._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() if !self.body.isEmpty { try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) } @@ -2949,7 +3074,7 @@ extension Compiler_Protobuf_ClassMethod: SwiftProtobuf.Message, SwiftProtobuf._M public static func ==(lhs: Compiler_Protobuf_ClassMethod, rhs: Compiler_Protobuf_ClassMethod) -> Bool { if lhs._key != rhs._key {return false} if lhs.isStatic != rhs.isStatic {return false} - if lhs.parameters != rhs.parameters {return false} + if lhs._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -2958,7 +3083,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() { @@ -2966,7 +3091,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 @@ -2975,9 +3100,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) } @@ -2988,7 +3117,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} @@ -2998,7 +3127,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() { @@ -3006,7 +3135,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) }() @@ -3020,9 +3149,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) } @@ -3036,7 +3165,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} @@ -4120,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 } @@ -4189,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 } @@ -5262,7 +5469,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() { @@ -5270,36 +5477,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 } } @@ -5310,29 +5489,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 @@ -5341,7 +5508,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() { @@ -5349,30 +5516,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.decodeRepeatedMessageField(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 } } @@ -5383,33 +5530,25 @@ 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) - } - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 4) + try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) } + try { if let v = self._parameters { + 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._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5418,7 +5557,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() { @@ -5426,28 +5565,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 } } @@ -5458,25 +5577,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 @@ -5485,7 +5596,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() { @@ -5493,29 +5604,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 } } @@ -5526,28 +5617,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} @@ -5728,7 +5811,7 @@ extension Compiler_Protobuf_FunctionExpression: SwiftProtobuf.Message, SwiftProt switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() case 2: try { try decoder.decodeSingularEnumField(value: &self.type) }() - case 3: try { try decoder.decodeRepeatedMessageField(value: &self.parameters) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } @@ -5736,15 +5819,19 @@ extension Compiler_Protobuf_FunctionExpression: SwiftProtobuf.Message, SwiftProt } 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.name.isEmpty { try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) } if self.type != .plain { try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) } - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 3) - } + try { if let v = self._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() if !self.body.isEmpty { try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) } @@ -5754,7 +5841,7 @@ extension Compiler_Protobuf_FunctionExpression: SwiftProtobuf.Message, SwiftProt public static func ==(lhs: Compiler_Protobuf_FunctionExpression, rhs: Compiler_Protobuf_FunctionExpression) -> Bool { if lhs.name != rhs.name {return false} if lhs.type != rhs.type {return false} - if lhs.parameters != rhs.parameters {return false} + if lhs._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5767,7 +5854,7 @@ extension Compiler_Protobuf_ArrowFunctionExpression: SwiftProtobuf.Message, Swif fileprivate class _StorageClass { var _type: Compiler_Protobuf_FunctionType = .plain - var _parameters: [Compiler_Protobuf_Parameter] = [] + var _parameters: Compiler_Protobuf_Parameters? = nil var _body: Compiler_Protobuf_ArrowFunctionExpression.OneOf_Body? // This property is used as the initial default value for new instances of the type. @@ -5801,7 +5888,7 @@ extension Compiler_Protobuf_ArrowFunctionExpression: SwiftProtobuf.Message, Swif // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &_storage._type) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._parameters) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._parameters) }() case 3: try { var v: Compiler_Protobuf_Statement? var hadOneofValue = false @@ -5843,9 +5930,9 @@ extension Compiler_Protobuf_ArrowFunctionExpression: SwiftProtobuf.Message, Swif if _storage._type != .plain { try visitor.visitSingularEnumField(value: _storage._type, fieldNumber: 1) } - if !_storage._parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: _storage._parameters, fieldNumber: 2) - } + try { if let v = _storage._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() switch _storage._body { case .block?: try { guard case .block(let v)? = _storage._body else { preconditionFailure() } diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index 56fd5fbdc..b9ce69147 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -16,12 +16,14 @@ syntax = "proto3"; package compiler.protobuf; message AST { - repeated Statement statements = 1; + string leadingComments = 1; + repeated Statement statements = 2; } // A parameter in a function declaration. Not an expression on its own. message Parameter { string name = 1; + Expression defaultValue = 2; } message EmptyStatement { @@ -65,10 +67,15 @@ enum FunctionType { ASYNC_GENERATOR = 3; } +message Parameters { + repeated Parameter parameters = 1; + bool hasRestElement = 2; +} + message FunctionDeclaration { string name = 1; FunctionType type = 2; - repeated Parameter parameters = 3; + Parameters parameters = 3; repeated Statement body = 4; } @@ -91,25 +98,25 @@ message ClassProperty { } message ClassConstructor { - repeated Parameter parameters = 1; + Parameters parameters = 1; repeated Statement body = 2; } message ClassMethod { PropertyKey key = 1; bool isStatic = 2; - repeated Parameter parameters = 3; + Parameters parameters = 3; repeated Statement body = 4; } 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; @@ -312,42 +319,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; - repeated Parameter 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 { @@ -372,13 +363,13 @@ message FunctionExpression { // The name is optional for function expressions string name = 1; FunctionType type = 2; - repeated Parameter parameters = 3; + Parameters parameters = 3; repeated Statement body = 4; } message ArrowFunctionExpression { FunctionType type = 1; - repeated Parameter parameters = 2; + Parameters parameters = 2; // The body can either be an expression or a block statement. oneof body { Statement block = 3; diff --git a/Sources/Fuzzilli/Protobuf/gen_programproto.py b/Sources/Fuzzilli/Protobuf/gen_programproto.py index 0018ac2a6..2055904e9 100644 --- a/Sources/Fuzzilli/Protobuf/gen_programproto.py +++ b/Sources/Fuzzilli/Protobuf/gen_programproto.py @@ -9,7 +9,7 @@ OPCODESSWIFT_FILE = "../FuzzIL/Opcodes.swift" -START = f"// Copyright {datetime.date.today().year} Google LLC" +START = f"// Copyright 2025 Google LLC" START += """ // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 7a1549674..97800aa14 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() {} @@ -1618,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 { @@ -1655,11 +1668,11 @@ public struct Fuzzilli_Protobuf_LoadString: Sendable { public var value: String = String() public var customName: String { - get {return _customName ?? String()} + get {_customName ?? String()} set {_customName = newValue} } /// Returns true if `customName` has been explicitly set. - public var hasCustomName: Bool {return self._customName != nil} + 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} @@ -1828,11 +1841,11 @@ public struct Fuzzilli_Protobuf_BeginObjectLiteralMethod: Sendable { public var methodName: String = String() public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -1859,11 +1872,11 @@ public struct Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -1906,29 +1919,7 @@ public struct Fuzzilli_Protobuf_EndObjectLiteralGetter: Sendable { 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 - // methods supported on all messages. - - public var propertyName: String = String() - - public var unknownFields = SwiftProtobuf.UnknownStorage() - - public init() {} -} - -public struct Fuzzilli_Protobuf_EndObjectLiteralSetter: 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 { +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. @@ -1938,42 +1929,29 @@ public struct Fuzzilli_Protobuf_EndObjectLiteral: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassDefinition: Sendable { +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 hasSuperclass_p: Bool = false - - public var isExpression: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_BeginClassConstructor: Sendable { +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 // methods supported on all messages. - public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} - set {_parameters = newValue} - } - /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} - /// Clears the value of `parameters`. Subsequent reads from it will return its default value. - public mutating func clearParameters() {self._parameters = nil} + public var propertyName: String = String() public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassConstructor: Sendable { +public struct Fuzzilli_Protobuf_EndObjectLiteralSetter: 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. @@ -1983,90 +1961,61 @@ public struct Fuzzilli_Protobuf_EndClassConstructor: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_ClassAddInstanceProperty: Sendable { +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 propertyName: String = String() - - public var hasValue_p: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_ClassAddInstanceElement: Sendable { +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 index: Int64 = 0 - - public var hasValue_p: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: Sendable { +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 // methods supported on all messages. - public var hasValue_p: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_BeginClassInstanceMethod: Sendable { +public struct Fuzzilli_Protobuf_BeginClassDefinition: 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 methodName: String = String() - - public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} - set {_parameters = newValue} - } - /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} - /// Clears the value of `parameters`. Subsequent reads from it will return its default value. - public mutating func clearParameters() {self._parameters = nil} - - public var unknownFields = SwiftProtobuf.UnknownStorage() - - public init() {} - - fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil -} + public var hasSuperclass_p: Bool = false -public struct Fuzzilli_Protobuf_EndClassInstanceMethod: 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 isExpression: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: Sendable { +public struct Fuzzilli_Protobuf_BeginClassConstructor: 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 parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2077,7 +2026,7 @@ public struct Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: Sendable { fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassInstanceComputedMethod: Sendable { +public struct Fuzzilli_Protobuf_EndClassConstructor: 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. @@ -2087,101 +2036,78 @@ public struct Fuzzilli_Protobuf_EndClassInstanceComputedMethod: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassInstanceGetter: Sendable { +public struct Fuzzilli_Protobuf_ClassAddProperty: 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 propertyName: String = String() - public var unknownFields = SwiftProtobuf.UnknownStorage() - - public init() {} -} + public var hasValue_p: Bool = false -public struct Fuzzilli_Protobuf_EndClassInstanceGetter: 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_BeginClassInstanceSetter: Sendable { +public struct Fuzzilli_Protobuf_ClassAddElement: 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 propertyName: String = String() - - public var unknownFields = SwiftProtobuf.UnknownStorage() + public var index: Int64 = 0 - public init() {} -} + public var hasValue_p: Bool = false -public struct Fuzzilli_Protobuf_EndClassInstanceSetter: 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_ClassAddStaticProperty: Sendable { +public struct Fuzzilli_Protobuf_ClassAddComputedProperty: 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 propertyName: String = String() - public var hasValue_p: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() - - public init() {} -} - -public struct Fuzzilli_Protobuf_ClassAddStaticElement: 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 index: Int64 = 0 - - public var hasValue_p: Bool = false + public var isStatic: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_ClassAddStaticComputedProperty: Sendable { +public struct Fuzzilli_Protobuf_BeginClassMethod: 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 hasValue_p: Bool = false - - public var unknownFields = SwiftProtobuf.UnknownStorage() + public var methodName: String = String() - public init() {} -} + public var parameters: Fuzzilli_Protobuf_Parameters { + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} + set {_parameters = newValue} + } + /// Returns true if `parameters` has been explicitly set. + public var hasParameters: Bool {self._parameters != nil} + /// Clears the value of `parameters`. Subsequent reads from it will return its default value. + public mutating func clearParameters() {self._parameters = nil} -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 - // methods supported on all messages. + public var isStatic: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassStaticInitializer: Sendable { +public struct Fuzzilli_Protobuf_EndClassMethod: 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. @@ -2191,22 +2117,22 @@ public struct Fuzzilli_Protobuf_EndClassStaticInitializer: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassStaticMethod: Sendable { +public struct Fuzzilli_Protobuf_BeginClassComputedMethod: 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 methodName: String = String() - public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} + public var isStatic: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -2214,7 +2140,7 @@ public struct Fuzzilli_Protobuf_BeginClassStaticMethod: Sendable { fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassStaticMethod: Sendable { +public struct Fuzzilli_Protobuf_EndClassComputedMethod: 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. @@ -2224,28 +2150,21 @@ public struct Fuzzilli_Protobuf_EndClassStaticMethod: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassStaticComputedMethod: Sendable { +public struct Fuzzilli_Protobuf_BeginClassGetter: 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 parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} - set {_parameters = newValue} - } - /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} - /// Clears the value of `parameters`. Subsequent reads from it will return its default value. - public mutating func clearParameters() {self._parameters = nil} + public var propertyName: String = String() + + public var isStatic: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassStaticComputedMethod: Sendable { +public struct Fuzzilli_Protobuf_EndClassGetter: 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. @@ -2255,19 +2174,19 @@ public struct Fuzzilli_Protobuf_EndClassStaticComputedMethod: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassStaticGetter: Sendable { +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 propertyName: String = String() + public var isStatic: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_EndClassStaticGetter: Sendable { +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. @@ -2277,19 +2196,21 @@ public struct Fuzzilli_Protobuf_EndClassStaticGetter: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginClassStaticSetter: Sendable { +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 // methods supported on all messages. public var propertyName: String = String() + public var isStatic: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_EndClassStaticSetter: Sendable { +public struct Fuzzilli_Protobuf_EndClassSetter: 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. @@ -2299,44 +2220,39 @@ public struct Fuzzilli_Protobuf_EndClassStaticSetter: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: Sendable { +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 propertyName: String = String() - - public var hasValue_p: Bool = false + public var isStatic: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: Sendable { +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 methodName: String = String() + public var unknownFields = SwiftProtobuf.UnknownStorage() - public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} - set {_parameters = newValue} - } - /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} - /// Clears the value of `parameters`. Subsequent reads from it will return its default value. - public mutating func clearParameters() {self._parameters = nil} + 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 + // methods supported on all messages. public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassPrivateInstanceMethod: Sendable { +public struct Fuzzilli_Protobuf_EndClassStaticInitializer: 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. @@ -2346,7 +2262,7 @@ public struct Fuzzilli_Protobuf_EndClassPrivateInstanceMethod: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: Sendable { +public struct Fuzzilli_Protobuf_ClassAddPrivateProperty: 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. @@ -2355,12 +2271,14 @@ public struct Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: Sendable { public var hasValue_p: Bool = false + public var isStatic: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} } -public struct Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: Sendable { +public struct Fuzzilli_Protobuf_BeginClassPrivateMethod: 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. @@ -2368,14 +2286,16 @@ public struct Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: Sendable { public var methodName: String = String() public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} + public var isStatic: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -2383,7 +2303,7 @@ public struct Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: Sendable { fileprivate var _parameters: Fuzzilli_Protobuf_Parameters? = nil } -public struct Fuzzilli_Protobuf_EndClassPrivateStaticMethod: Sendable { +public struct Fuzzilli_Protobuf_EndClassPrivateMethod: 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. @@ -2721,11 +2641,11 @@ public struct Fuzzilli_Protobuf_BeginPlainFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2755,11 +2675,11 @@ public struct Fuzzilli_Protobuf_BeginArrowFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2786,11 +2706,11 @@ public struct Fuzzilli_Protobuf_BeginGeneratorFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2820,11 +2740,11 @@ public struct Fuzzilli_Protobuf_BeginAsyncFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2854,11 +2774,11 @@ public struct Fuzzilli_Protobuf_BeginAsyncArrowFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2885,11 +2805,11 @@ public struct Fuzzilli_Protobuf_BeginAsyncGeneratorFunction: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -2919,11 +2839,11 @@ public struct Fuzzilli_Protobuf_BeginConstructor: Sendable { // methods supported on all messages. public var parameters: Fuzzilli_Protobuf_Parameters { - get {return _parameters ?? Fuzzilli_Protobuf_Parameters()} + get {_parameters ?? Fuzzilli_Protobuf_Parameters()} set {_parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return self._parameters != nil} + public var hasParameters: Bool {self._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {self._parameters = nil} @@ -3934,11 +3854,11 @@ public struct Fuzzilli_Protobuf_CreateWasmGlobal: Sendable { // methods supported on all messages. public var wasmGlobal: Fuzzilli_Protobuf_WasmGlobal { - get {return _wasmGlobal ?? Fuzzilli_Protobuf_WasmGlobal()} + get {_wasmGlobal ?? Fuzzilli_Protobuf_WasmGlobal()} set {_wasmGlobal = newValue} } /// Returns true if `wasmGlobal` has been explicitly set. - public var hasWasmGlobal: Bool {return self._wasmGlobal != nil} + public var hasWasmGlobal: Bool {self._wasmGlobal != nil} /// Clears the value of `wasmGlobal`. Subsequent reads from it will return its default value. public mutating func clearWasmGlobal() {self._wasmGlobal = nil} @@ -3955,11 +3875,11 @@ public struct Fuzzilli_Protobuf_CreateWasmMemory: Sendable { // methods supported on all messages. public var wasmMemory: Fuzzilli_Protobuf_WasmMemory { - get {return _wasmMemory ?? Fuzzilli_Protobuf_WasmMemory()} + get {_wasmMemory ?? Fuzzilli_Protobuf_WasmMemory()} set {_wasmMemory = newValue} } /// Returns true if `wasmMemory` has been explicitly set. - public var hasWasmMemory: Bool {return self._wasmMemory != nil} + public var hasWasmMemory: Bool {self._wasmMemory != nil} /// Clears the value of `wasmMemory`. Subsequent reads from it will return its default value. public mutating func clearWasmMemory() {self._wasmMemory = nil} @@ -3976,22 +3896,22 @@ public struct Fuzzilli_Protobuf_CreateWasmTable: Sendable { // methods supported on all messages. public var elementType: Fuzzilli_Protobuf_WasmILType { - get {return _elementType ?? Fuzzilli_Protobuf_WasmILType()} + get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} set {_elementType = newValue} } /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {return self._elementType != nil} + 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 {return _maxSize ?? 0} + get {_maxSize ?? 0} set {_maxSize = newValue} } /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {return self._maxSize != nil} + 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} @@ -4122,8 +4042,6 @@ public struct Fuzzilli_Protobuf_WasmReturn: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var returnTypes: [Fuzzilli_Protobuf_WasmILType] = [] - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -4182,9 +4100,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() @@ -4196,9 +4112,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() @@ -4210,9 +4124,9 @@ public struct Fuzzilli_Protobuf_WasmJsCall: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var parameterCount: Int32 = 0 - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -4760,11 +4674,11 @@ public struct Fuzzilli_Protobuf_WasmMemory: Sendable { public var minPages: Int64 = 0 public var maxPages: Int64 { - get {return _maxPages ?? 0} + get {_maxPages ?? 0} set {_maxPages = newValue} } /// Returns true if `maxPages` has been explicitly set. - public var hasMaxPages: Bool {return self._maxPages != nil} + public var hasMaxPages: Bool {self._maxPages != nil} /// Clears the value of `maxPages`. Subsequent reads from it will return its default value. public mutating func clearMaxPages() {self._maxPages = nil} @@ -4785,11 +4699,11 @@ public struct Fuzzilli_Protobuf_WasmDefineGlobal: Sendable { // methods supported on all messages. public var wasmGlobal: Fuzzilli_Protobuf_WasmGlobal { - get {return _wasmGlobal ?? Fuzzilli_Protobuf_WasmGlobal()} + get {_wasmGlobal ?? Fuzzilli_Protobuf_WasmGlobal()} set {_wasmGlobal = newValue} } /// Returns true if `wasmGlobal` has been explicitly set. - public var hasWasmGlobal: Bool {return self._wasmGlobal != nil} + public var hasWasmGlobal: Bool {self._wasmGlobal != nil} /// Clears the value of `wasmGlobal`. Subsequent reads from it will return its default value. public mutating func clearWasmGlobal() {self._wasmGlobal = nil} @@ -4822,11 +4736,11 @@ public struct Fuzzilli_Protobuf_IndexedWasmSignature: Sendable { public var index: Int64 = 0 public var signature: Fuzzilli_Protobuf_WasmSignature { - get {return _signature ?? Fuzzilli_Protobuf_WasmSignature()} + get {_signature ?? Fuzzilli_Protobuf_WasmSignature()} set {_signature = newValue} } /// Returns true if `signature` has been explicitly set. - public var hasSignature: Bool {return self._signature != nil} + public var hasSignature: Bool {self._signature != nil} /// Clears the value of `signature`. Subsequent reads from it will return its default value. public mutating func clearSignature() {self._signature = nil} @@ -4843,22 +4757,22 @@ public struct Fuzzilli_Protobuf_WasmDefineTable: Sendable { // methods supported on all messages. public var elementType: Fuzzilli_Protobuf_WasmILType { - get {return _elementType ?? Fuzzilli_Protobuf_WasmILType()} + get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} set {_elementType = newValue} } /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {return self._elementType != nil} + 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 {return _maxSize ?? 0} + get {_maxSize ?? 0} set {_maxSize = newValue} } /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {return self._maxSize != nil} + 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} @@ -4880,11 +4794,11 @@ public struct Fuzzilli_Protobuf_WasmDefineMemory: Sendable { // methods supported on all messages. public var wasmMemory: Fuzzilli_Protobuf_WasmMemory { - get {return _wasmMemory ?? Fuzzilli_Protobuf_WasmMemory()} + get {_wasmMemory ?? Fuzzilli_Protobuf_WasmMemory()} set {_wasmMemory = newValue} } /// Returns true if `wasmMemory` has been explicitly set. - public var hasWasmMemory: Bool {return self._wasmMemory != nil} + public var hasWasmMemory: Bool {self._wasmMemory != nil} /// Clears the value of `wasmMemory`. Subsequent reads from it will return its default value. public mutating func clearWasmMemory() {self._wasmMemory = nil} @@ -4901,11 +4815,11 @@ public struct Fuzzilli_Protobuf_WasmLoadGlobal: Sendable { // methods supported on all messages. public var globalType: Fuzzilli_Protobuf_WasmILType { - get {return _globalType ?? Fuzzilli_Protobuf_WasmILType()} + get {_globalType ?? Fuzzilli_Protobuf_WasmILType()} set {_globalType = newValue} } /// Returns true if `globalType` has been explicitly set. - public var hasGlobalType: Bool {return self._globalType != nil} + public var hasGlobalType: Bool {self._globalType != nil} /// Clears the value of `globalType`. Subsequent reads from it will return its default value. public mutating func clearGlobalType() {self._globalType = nil} @@ -4922,11 +4836,11 @@ public struct Fuzzilli_Protobuf_WasmStoreGlobal: Sendable { // methods supported on all messages. public var globalType: Fuzzilli_Protobuf_WasmILType { - get {return _globalType ?? Fuzzilli_Protobuf_WasmILType()} + get {_globalType ?? Fuzzilli_Protobuf_WasmILType()} set {_globalType = newValue} } /// Returns true if `globalType` has been explicitly set. - public var hasGlobalType: Bool {return self._globalType != nil} + public var hasGlobalType: Bool {self._globalType != nil} /// Clears the value of `globalType`. Subsequent reads from it will return its default value. public mutating func clearGlobalType() {self._globalType = nil} @@ -4937,40 +4851,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 {return _elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {return 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 {return _maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {return 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 { @@ -4978,34 +4866,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 {return _elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {return 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 {return _maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {return 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 { @@ -5047,9 +4910,9 @@ public struct Fuzzilli_Protobuf_WasmCallDirect: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var parameterCount: Int32 = 0 - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5061,9 +4924,7 @@ public struct Fuzzilli_Protobuf_WasmReturnCallDirect: 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() @@ -5147,9 +5008,7 @@ public struct Fuzzilli_Protobuf_WasmBeginBlock: 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() @@ -5161,7 +5020,7 @@ public struct Fuzzilli_Protobuf_WasmEndBlock: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5173,9 +5032,7 @@ public struct Fuzzilli_Protobuf_WasmBeginLoop: 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() @@ -5187,7 +5044,7 @@ public struct Fuzzilli_Protobuf_WasmEndLoop: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5199,9 +5056,7 @@ public struct Fuzzilli_Protobuf_WasmBeginTryTable: 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 catches: [Fuzzilli_Protobuf_WasmCatchKind] = [] @@ -5215,7 +5070,7 @@ public struct Fuzzilli_Protobuf_WasmEndTryTable: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5227,9 +5082,7 @@ public struct Fuzzilli_Protobuf_WasmBeginTry: 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() @@ -5241,7 +5094,7 @@ public struct Fuzzilli_Protobuf_WasmBeginCatchAll: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var inputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var blockOutputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5253,9 +5106,9 @@ public struct Fuzzilli_Protobuf_WasmBeginCatch: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var blockOutputCount: Int32 = 0 - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var labelParameterCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5267,7 +5120,7 @@ public struct Fuzzilli_Protobuf_WasmEndTry: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var blockOutputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5279,9 +5132,7 @@ public struct Fuzzilli_Protobuf_WasmBeginTryDelegate: 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() @@ -5293,7 +5144,7 @@ public struct Fuzzilli_Protobuf_WasmEndTryDelegate: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5305,8 +5156,6 @@ public struct Fuzzilli_Protobuf_WasmThrow: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -5337,8 +5186,6 @@ public struct Fuzzilli_Protobuf_WasmDefineTag: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -5349,8 +5196,6 @@ public struct Fuzzilli_Protobuf_WasmBranch: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameters: [Fuzzilli_Protobuf_WasmILType] = [] - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -5361,8 +5206,6 @@ public struct Fuzzilli_Protobuf_WasmBranchIf: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameters: [Fuzzilli_Protobuf_WasmILType] = [] - public var hint: Fuzzilli_Protobuf_WasmBranchHint = .branchhintNone public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5375,8 +5218,6 @@ public struct Fuzzilli_Protobuf_WasmBranchTable: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameters: [Fuzzilli_Protobuf_WasmILType] = [] - public var valueCount: UInt32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5389,20 +5230,9 @@ public struct Fuzzilli_Protobuf_WasmReassign: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var variableType: Fuzzilli_Protobuf_WasmILType { - get {return _variableType ?? Fuzzilli_Protobuf_WasmILType()} - set {_variableType = newValue} - } - /// Returns true if `variableType` has been explicitly set. - public var hasVariableType: Bool {return self._variableType != nil} - /// Clears the value of `variableType`. Subsequent reads from it will return its default value. - public mutating func clearVariableType() {self._variableType = nil} - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _variableType: Fuzzilli_Protobuf_WasmILType? = nil } public struct Fuzzilli_Protobuf_WasmBeginIf: Sendable { @@ -5410,9 +5240,7 @@ public struct Fuzzilli_Protobuf_WasmBeginIf: 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 inverted: Bool = false @@ -5428,9 +5256,9 @@ public struct Fuzzilli_Protobuf_WasmBeginElse: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var parameterCount: Int32 = 0 - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5442,7 +5270,7 @@ public struct Fuzzilli_Protobuf_WasmEndIf: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -5709,17 +5537,45 @@ public struct Fuzzilli_Protobuf_WasmDefineSignatureType: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_WasmDefineAdHocSignatureType: 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 parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + + public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType: 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 parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] + + public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_WasmDefineArrayType: 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 {return _elementType ?? Fuzzilli_Protobuf_WasmILType()} + get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} set {_elementType = newValue} } /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {return self._elementType != nil} + 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} @@ -5738,11 +5594,11 @@ public struct Fuzzilli_Protobuf_WasmStructField: Sendable { // methods supported on all messages. public var type: Fuzzilli_Protobuf_WasmILType { - get {return _type ?? Fuzzilli_Protobuf_WasmILType()} + get {_type ?? Fuzzilli_Protobuf_WasmILType()} set {_type = newValue} } /// Returns true if `type` has been explicitly set. - public var hasType: Bool {return self._type != nil} + public var hasType: Bool {self._type != nil} /// Clears the value of `type`. Subsequent reads from it will return its default value. public mutating func clearType() {self._type = nil} @@ -5849,6 +5705,16 @@ public struct Fuzzilli_Protobuf_WasmStructNewDefault: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_WasmStructNew: 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_WasmStructGet: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -5881,11 +5747,11 @@ public struct Fuzzilli_Protobuf_WasmRefNull: Sendable { // methods supported on all messages. public var type: Fuzzilli_Protobuf_WasmILType { - get {return _type ?? Fuzzilli_Protobuf_WasmILType()} + get {_type ?? Fuzzilli_Protobuf_WasmILType()} set {_type = newValue} } /// Returns true if `type` has been explicitly set. - public var hasType: Bool {return self._type != nil} + public var hasType: Bool {self._type != nil} /// Clears the value of `type`. Subsequent reads from it will return its default value. public mutating func clearType() {self._type = nil} @@ -5906,11 +5772,65 @@ public struct Fuzzilli_Protobuf_WasmRefIsNull: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_WasmRefEq: 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_WasmRefTest: 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 type: Fuzzilli_Protobuf_WasmILType { + get {_type ?? Fuzzilli_Protobuf_WasmILType()} + set {_type = newValue} + } + /// Returns true if `type` has been explicitly set. + public var hasType: Bool {self._type != nil} + /// Clears the value of `type`. Subsequent reads from it will return its default value. + public mutating func clearType() {self._type = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _type: Fuzzilli_Protobuf_WasmILType? = nil +} + +public struct Fuzzilli_Protobuf_WasmRefCast: 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 type: Fuzzilli_Protobuf_WasmILType { + get {_type ?? Fuzzilli_Protobuf_WasmILType()} + set {_type = newValue} + } + /// Returns true if `type` has been explicitly set. + public var hasType: Bool {self._type != nil} + /// Clears the value of `type`. Subsequent reads from it will return its default value. + public mutating func clearType() {self._type = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _type: Fuzzilli_Protobuf_WasmILType? = nil +} + public struct Fuzzilli_Protobuf_WasmRefI31: 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 isShared: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -6088,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" @@ -6194,7 +6134,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() { @@ -6204,6 +6144,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 } } @@ -6216,12 +6157,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 } @@ -6229,7 +6174,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() { @@ -6238,20 +6183,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 } @@ -6831,6 +6785,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") @@ -6880,6 +6872,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() @@ -6987,9 +7017,9 @@ extension Fuzzilli_Protobuf_EndClassConstructor: SwiftProtobuf.Message, SwiftPro } } -extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddInstanceProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddProperty" + 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() { @@ -6999,6 +7029,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 } } @@ -7011,20 +7042,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() { @@ -7034,6 +7069,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 } } @@ -7046,20 +7082,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() { @@ -7068,6 +7108,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 } } @@ -7077,19 +7118,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() { @@ -7099,6 +7144,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 } } @@ -7115,19 +7161,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 { @@ -7139,15 +7189,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() { @@ -7156,6 +7206,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 } } @@ -7169,18 +7220,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 { @@ -7192,15 +7247,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() { @@ -7209,6 +7264,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 } } @@ -7218,18 +7274,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 { @@ -7241,15 +7301,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_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() { @@ -7257,28 +7317,28 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi // 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 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceSetter, rhs: Fuzzilli_Protobuf_BeginClassInstanceSetter) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} + 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_EndClassInstanceSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceSetter" +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 { @@ -7290,15 +7350,15 @@ 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_EndClassComputedGetter, rhs: Fuzzilli_Protobuf_EndClassComputedGetter) -> 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_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() { @@ -7307,7 +7367,7 @@ extension Fuzzilli_Protobuf_ClassAddStaticProperty: SwiftProtobuf.Message, Swift // 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) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7317,58 +7377,42 @@ extension Fuzzilli_Protobuf_ClassAddStaticProperty: SwiftProtobuf.Message, Swift 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: 2) } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddStaticProperty) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassSetter, rhs: Fuzzilli_Protobuf_BeginClassSetter) -> 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_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_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 { - 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.decodeSingularInt64Field(value: &self.index) }() - 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.index != 0 { - try visitor.visitSingularInt64Field(value: self.index, 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_ClassAddStaticElement, rhs: Fuzzilli_Protobuf_ClassAddStaticElement) -> Bool { - if lhs.index != rhs.index {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} + public static func ==(lhs: Fuzzilli_Protobuf_EndClassSetter, rhs: Fuzzilli_Protobuf_EndClassSetter) -> Bool { 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_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() { @@ -7376,21 +7420,40 @@ 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) }() + case 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } } public func traverse(visitor: inout V) throws { - 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: 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} + 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 } @@ -7434,9 +7497,9 @@ extension Fuzzilli_Protobuf_EndClassStaticInitializer: SwiftProtobuf.Message, Sw } } -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") +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() { @@ -7444,217 +7507,9 @@ extension Fuzzilli_Protobuf_BeginClassStaticMethod: SwiftProtobuf.Message, Swift // 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) }() + 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 } } @@ -7667,113 +7522,24 @@ extension Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: SwiftProtobuf.Messa 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) }() - 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_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 - } - } - } - - 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) + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty) -> Bool { + 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_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") +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() { @@ -7783,6 +7549,7 @@ extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: SwiftProtobuf.Message 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 } } @@ -7799,19 +7566,23 @@ extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: SwiftProtobuf.Message 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_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 { @@ -7823,7 +7594,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 } @@ -11518,29 +11289,18 @@ extension Fuzzilli_Protobuf_Constf64: SwiftProtobuf.Message, SwiftProtobuf._Mess extension Fuzzilli_Protobuf_WasmReturn: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmReturn" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}returnTypes\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.decodeRepeatedMessageField(value: &self.returnTypes) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if !self.returnTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.returnTypes, fieldNumber: 1) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmReturn, rhs: Fuzzilli_Protobuf_WasmReturn) -> Bool { - if lhs.returnTypes != rhs.returnTypes {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -11645,7 +11405,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() { @@ -11653,26 +11413,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 } @@ -11680,7 +11435,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() { @@ -11688,26 +11443,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 } @@ -11715,7 +11465,7 @@ extension Fuzzilli_Protobuf_EndWasmFunction: SwiftProtobuf.Message, SwiftProtobu extension Fuzzilli_Protobuf_WasmJsCall: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmJsCall" - 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\u{1}outputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11723,26 +11473,26 @@ extension Fuzzilli_Protobuf_WasmJsCall: SwiftProtobuf.Message, SwiftProtobuf._Me // 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) }() + case 2: 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.parameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.parameterCount, 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: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmJsCall, rhs: Fuzzilli_Protobuf_WasmJsCall) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13236,48 +12986,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 } @@ -13285,48 +13005,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 } @@ -13407,7 +13097,7 @@ extension Fuzzilli_Protobuf_WasmCallIndirect: SwiftProtobuf.Message, SwiftProtob extension Fuzzilli_Protobuf_WasmCallDirect: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmCallDirect" - 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\u{1}outputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -13415,26 +13105,26 @@ extension Fuzzilli_Protobuf_WasmCallDirect: 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 { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() + case 2: 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.parameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.parameterCount, 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: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmCallDirect, rhs: Fuzzilli_Protobuf_WasmCallDirect) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13442,7 +13132,7 @@ extension Fuzzilli_Protobuf_WasmCallDirect: SwiftProtobuf.Message, SwiftProtobuf extension Fuzzilli_Protobuf_WasmReturnCallDirect: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmReturnCallDirect" - 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() { @@ -13450,26 +13140,21 @@ extension Fuzzilli_Protobuf_WasmReturnCallDirect: SwiftProtobuf.Message, SwiftPr // 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_WasmReturnCallDirect, rhs: Fuzzilli_Protobuf_WasmReturnCallDirect) -> 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 } @@ -13639,7 +13324,7 @@ extension Fuzzilli_Protobuf_WasmMemoryFill: SwiftProtobuf.Message, SwiftProtobuf extension Fuzzilli_Protobuf_WasmBeginBlock: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginBlock" - 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() { @@ -13647,26 +13332,21 @@ extension Fuzzilli_Protobuf_WasmBeginBlock: 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 { 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_WasmBeginBlock, rhs: Fuzzilli_Protobuf_WasmBeginBlock) -> 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 } @@ -13674,7 +13354,7 @@ extension Fuzzilli_Protobuf_WasmBeginBlock: SwiftProtobuf.Message, SwiftProtobuf extension Fuzzilli_Protobuf_WasmEndBlock: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndBlock" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\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() { @@ -13682,21 +13362,21 @@ extension Fuzzilli_Protobuf_WasmEndBlock: 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 { 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.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndBlock, rhs: Fuzzilli_Protobuf_WasmEndBlock) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13704,7 +13384,7 @@ extension Fuzzilli_Protobuf_WasmEndBlock: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmBeginLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginLoop" - 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() { @@ -13712,26 +13392,21 @@ extension Fuzzilli_Protobuf_WasmBeginLoop: 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 { 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_WasmBeginLoop, rhs: Fuzzilli_Protobuf_WasmBeginLoop) -> 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 } @@ -13739,7 +13414,7 @@ extension Fuzzilli_Protobuf_WasmBeginLoop: SwiftProtobuf.Message, SwiftProtobuf. extension Fuzzilli_Protobuf_WasmEndLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndLoop" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\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() { @@ -13747,21 +13422,21 @@ extension Fuzzilli_Protobuf_WasmEndLoop: 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.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndLoop, rhs: Fuzzilli_Protobuf_WasmEndLoop) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13769,7 +13444,7 @@ extension Fuzzilli_Protobuf_WasmEndLoop: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_WasmBeginTryTable: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginTryTable" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0\u{1}catches\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterCount\0\u{1}catches\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -13777,30 +13452,25 @@ extension Fuzzilli_Protobuf_WasmBeginTryTable: 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 3: try { try decoder.decodeRepeatedEnumField(value: &self.catches) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() + case 2: try { try decoder.decodeRepeatedEnumField(value: &self.catches) }() 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) } if !self.catches.isEmpty { - try visitor.visitPackedEnumField(value: self.catches, fieldNumber: 3) + try visitor.visitPackedEnumField(value: self.catches, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmBeginTryTable, rhs: Fuzzilli_Protobuf_WasmBeginTryTable) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} if lhs.catches != rhs.catches {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -13809,7 +13479,7 @@ extension Fuzzilli_Protobuf_WasmBeginTryTable: SwiftProtobuf.Message, SwiftProto extension Fuzzilli_Protobuf_WasmEndTryTable: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndTryTable" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\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() { @@ -13817,21 +13487,21 @@ extension Fuzzilli_Protobuf_WasmEndTryTable: 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.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndTryTable, rhs: Fuzzilli_Protobuf_WasmEndTryTable) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13839,7 +13509,7 @@ extension Fuzzilli_Protobuf_WasmEndTryTable: SwiftProtobuf.Message, SwiftProtobu extension Fuzzilli_Protobuf_WasmBeginTry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginTry" - 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() { @@ -13847,26 +13517,21 @@ extension Fuzzilli_Protobuf_WasmBeginTry: 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 { 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_WasmBeginTry, rhs: Fuzzilli_Protobuf_WasmBeginTry) -> 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 } @@ -13874,7 +13539,7 @@ extension Fuzzilli_Protobuf_WasmBeginTry: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmBeginCatchAll: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginCatchAll" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}blockOutputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -13882,21 +13547,21 @@ extension Fuzzilli_Protobuf_WasmBeginCatchAll: 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.inputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.blockOutputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.inputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.inputTypes, fieldNumber: 1) + if self.blockOutputCount != 0 { + try visitor.visitSingularInt32Field(value: self.blockOutputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmBeginCatchAll, rhs: Fuzzilli_Protobuf_WasmBeginCatchAll) -> Bool { - if lhs.inputTypes != rhs.inputTypes {return false} + if lhs.blockOutputCount != rhs.blockOutputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13904,7 +13569,7 @@ extension Fuzzilli_Protobuf_WasmBeginCatchAll: SwiftProtobuf.Message, SwiftProto extension Fuzzilli_Protobuf_WasmBeginCatch: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginCatch" - 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}blockOutputCount\0\u{1}labelParameterCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -13912,26 +13577,26 @@ extension Fuzzilli_Protobuf_WasmBeginCatch: 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 { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.blockOutputCount) }() + case 2: try { try decoder.decodeSingularInt32Field(value: &self.labelParameterCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) + if self.blockOutputCount != 0 { + try visitor.visitSingularInt32Field(value: self.blockOutputCount, fieldNumber: 1) } - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 2) + if self.labelParameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.labelParameterCount, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmBeginCatch, rhs: Fuzzilli_Protobuf_WasmBeginCatch) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.blockOutputCount != rhs.blockOutputCount {return false} + if lhs.labelParameterCount != rhs.labelParameterCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13939,7 +13604,7 @@ extension Fuzzilli_Protobuf_WasmBeginCatch: SwiftProtobuf.Message, SwiftProtobuf extension Fuzzilli_Protobuf_WasmEndTry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndTry" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}outputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}blockOutputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -13947,21 +13612,21 @@ extension Fuzzilli_Protobuf_WasmEndTry: SwiftProtobuf.Message, SwiftProtobuf._Me // 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.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.blockOutputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.blockOutputCount != 0 { + try visitor.visitSingularInt32Field(value: self.blockOutputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndTry, rhs: Fuzzilli_Protobuf_WasmEndTry) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.blockOutputCount != rhs.blockOutputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -13969,7 +13634,7 @@ extension Fuzzilli_Protobuf_WasmEndTry: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_WasmBeginTryDelegate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginTryDelegate" - 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() { @@ -13977,26 +13642,21 @@ extension Fuzzilli_Protobuf_WasmBeginTryDelegate: SwiftProtobuf.Message, SwiftPr // 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_WasmBeginTryDelegate, rhs: Fuzzilli_Protobuf_WasmBeginTryDelegate) -> 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 } @@ -14004,7 +13664,7 @@ extension Fuzzilli_Protobuf_WasmBeginTryDelegate: SwiftProtobuf.Message, SwiftPr extension Fuzzilli_Protobuf_WasmEndTryDelegate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndTryDelegate" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\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() { @@ -14012,21 +13672,21 @@ extension Fuzzilli_Protobuf_WasmEndTryDelegate: SwiftProtobuf.Message, SwiftProt // 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.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndTryDelegate, rhs: Fuzzilli_Protobuf_WasmEndTryDelegate) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14034,29 +13694,18 @@ extension Fuzzilli_Protobuf_WasmEndTryDelegate: SwiftProtobuf.Message, SwiftProt extension Fuzzilli_Protobuf_WasmThrow: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmThrow" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\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.decodeRepeatedMessageField(value: &self.parameterTypes) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmThrow, rhs: Fuzzilli_Protobuf_WasmThrow) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14102,29 +13751,18 @@ extension Fuzzilli_Protobuf_WasmRethrow: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_WasmDefineTag: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmDefineTag" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\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.decodeRepeatedMessageField(value: &self.parameterTypes) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } - public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } + public func traverse(visitor: inout V) throws { try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmDefineTag, rhs: Fuzzilli_Protobuf_WasmDefineTag) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14132,29 +13770,18 @@ extension Fuzzilli_Protobuf_WasmDefineTag: SwiftProtobuf.Message, SwiftProtobuf. extension Fuzzilli_Protobuf_WasmBranch: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBranch" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\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.decodeRepeatedMessageField(value: &self.parameters) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 1) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmBranch, rhs: Fuzzilli_Protobuf_WasmBranch) -> Bool { - if lhs.parameters != rhs.parameters {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14162,7 +13789,7 @@ extension Fuzzilli_Protobuf_WasmBranch: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_WasmBranchIf: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBranchIf" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0\u{1}hint\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\u{2}hint\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -14170,7 +13797,6 @@ extension Fuzzilli_Protobuf_WasmBranchIf: 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 { try decoder.decodeRepeatedMessageField(value: &self.parameters) }() case 2: try { try decoder.decodeSingularEnumField(value: &self.hint) }() default: break } @@ -14178,9 +13804,6 @@ extension Fuzzilli_Protobuf_WasmBranchIf: SwiftProtobuf.Message, SwiftProtobuf._ } public func traverse(visitor: inout V) throws { - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 1) - } if self.hint != .branchhintNone { try visitor.visitSingularEnumField(value: self.hint, fieldNumber: 2) } @@ -14188,7 +13811,6 @@ extension Fuzzilli_Protobuf_WasmBranchIf: SwiftProtobuf.Message, SwiftProtobuf._ } public static func ==(lhs: Fuzzilli_Protobuf_WasmBranchIf, rhs: Fuzzilli_Protobuf_WasmBranchIf) -> Bool { - if lhs.parameters != rhs.parameters {return false} if lhs.hint != rhs.hint {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -14197,7 +13819,7 @@ extension Fuzzilli_Protobuf_WasmBranchIf: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmBranchTable: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBranchTable" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0\u{1}valueCount\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\u{2}valueCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -14205,7 +13827,6 @@ extension Fuzzilli_Protobuf_WasmBranchTable: 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.parameters) }() case 2: try { try decoder.decodeSingularUInt32Field(value: &self.valueCount) }() default: break } @@ -14213,9 +13834,6 @@ extension Fuzzilli_Protobuf_WasmBranchTable: SwiftProtobuf.Message, SwiftProtobu } public func traverse(visitor: inout V) throws { - if !self.parameters.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 1) - } if self.valueCount != 0 { try visitor.visitSingularUInt32Field(value: self.valueCount, fieldNumber: 2) } @@ -14223,7 +13841,6 @@ extension Fuzzilli_Protobuf_WasmBranchTable: SwiftProtobuf.Message, SwiftProtobu } public static func ==(lhs: Fuzzilli_Protobuf_WasmBranchTable, rhs: Fuzzilli_Protobuf_WasmBranchTable) -> Bool { - if lhs.parameters != rhs.parameters {return false} if lhs.valueCount != rhs.valueCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -14232,33 +13849,18 @@ extension Fuzzilli_Protobuf_WasmBranchTable: SwiftProtobuf.Message, SwiftProtobu extension Fuzzilli_Protobuf_WasmReassign: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmReassign" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}variableType\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._variableType) }() - 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._variableType { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmReassign, rhs: Fuzzilli_Protobuf_WasmReassign) -> Bool { - if lhs._variableType != rhs._variableType {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14266,7 +13868,7 @@ extension Fuzzilli_Protobuf_WasmReassign: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmBeginIf: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginIf" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0\u{1}inverted\0\u{1}hint\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterCount\0\u{2}\u{2}inverted\0\u{1}hint\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -14274,8 +13876,7 @@ extension Fuzzilli_Protobuf_WasmBeginIf: 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.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.inverted) }() case 4: try { try decoder.decodeSingularEnumField(value: &self.hint) }() default: break @@ -14284,11 +13885,8 @@ extension Fuzzilli_Protobuf_WasmBeginIf: SwiftProtobuf.Message, SwiftProtobuf._M } 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) } if self.inverted != false { try visitor.visitSingularBoolField(value: self.inverted, fieldNumber: 3) @@ -14300,8 +13898,7 @@ extension Fuzzilli_Protobuf_WasmBeginIf: SwiftProtobuf.Message, SwiftProtobuf._M } public static func ==(lhs: Fuzzilli_Protobuf_WasmBeginIf, rhs: Fuzzilli_Protobuf_WasmBeginIf) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} if lhs.inverted != rhs.inverted {return false} if lhs.hint != rhs.hint {return false} if lhs.unknownFields != rhs.unknownFields {return false} @@ -14311,7 +13908,7 @@ extension Fuzzilli_Protobuf_WasmBeginIf: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_WasmBeginElse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmBeginElse" - 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\u{1}outputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -14319,26 +13916,26 @@ extension Fuzzilli_Protobuf_WasmBeginElse: 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 { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() + case 2: 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.parameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.parameterCount, 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: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmBeginElse, rhs: Fuzzilli_Protobuf_WasmBeginElse) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14346,7 +13943,7 @@ extension Fuzzilli_Protobuf_WasmBeginElse: SwiftProtobuf.Message, SwiftProtobuf. extension Fuzzilli_Protobuf_WasmEndIf: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmEndIf" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\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() { @@ -14354,21 +13951,21 @@ extension Fuzzilli_Protobuf_WasmEndIf: SwiftProtobuf.Message, SwiftProtobuf._Mes // 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.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 1) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmEndIf, rhs: Fuzzilli_Protobuf_WasmEndIf) -> Bool { - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -14994,6 +14591,76 @@ extension Fuzzilli_Protobuf_WasmDefineSignatureType: SwiftProtobuf.Message, Swif } } +extension Fuzzilli_Protobuf_WasmDefineAdHocSignatureType: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmDefineAdHocSignatureType" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\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.decodeRepeatedMessageField(value: &self.parameterTypes) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + 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) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType, rhs: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType) -> Bool { + if lhs.parameterTypes != rhs.parameterTypes {return false} + if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmDefineAdHocModuleSignatureType" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\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.decodeRepeatedMessageField(value: &self.parameterTypes) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + 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) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType, rhs: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType) -> Bool { + if lhs.parameterTypes != rhs.parameterTypes {return false} + if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_WasmDefineArrayType: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmDefineArrayType" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}elementType\0\u{1}mutability\0") @@ -15265,6 +14932,25 @@ extension Fuzzilli_Protobuf_WasmStructNewDefault: SwiftProtobuf.Message, SwiftPr } } +extension Fuzzilli_Protobuf_WasmStructNew: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmStructNew" + 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_WasmStructNew, rhs: Fuzzilli_Protobuf_WasmStructNew) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_WasmStructGet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmStructGet" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}fieldIndex\0\u{1}isSigned\0") @@ -15383,8 +15069,8 @@ extension Fuzzilli_Protobuf_WasmRefIsNull: SwiftProtobuf.Message, SwiftProtobuf. } } -extension Fuzzilli_Protobuf_WasmRefI31: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".WasmRefI31" +extension Fuzzilli_Protobuf_WasmRefEq: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmRefEq" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -15396,7 +15082,105 @@ extension Fuzzilli_Protobuf_WasmRefI31: SwiftProtobuf.Message, SwiftProtobuf._Me try unknownFields.traverse(visitor: &visitor) } + public static func ==(lhs: Fuzzilli_Protobuf_WasmRefEq, rhs: Fuzzilli_Protobuf_WasmRefEq) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_WasmRefTest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmRefTest" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}type\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._type) }() + 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._type { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_WasmRefTest, rhs: Fuzzilli_Protobuf_WasmRefTest) -> Bool { + if lhs._type != rhs._type {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_WasmRefCast: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmRefCast" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}type\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._type) }() + 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._type { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_WasmRefCast, rhs: Fuzzilli_Protobuf_WasmRefCast) -> Bool { + if lhs._type != rhs._type {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_WasmRefI31: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WasmRefI31" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}isShared\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.isShared) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.isShared != false { + try visitor.visitSingularBoolField(value: self.isShared, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + public static func ==(lhs: Fuzzilli_Protobuf_WasmRefI31, rhs: Fuzzilli_Protobuf_WasmRefI31) -> Bool { + if lhs.isShared != rhs.isShared {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -15783,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 72266a1fb..cdb4eb12f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -19,10 +19,12 @@ package fuzzilli.protobuf; message Parameters { uint32 count = 1; bool hasRest = 2; + repeated uint32 defaultParameterIndices = 3; } message LoadInteger { int64 value = 1; + optional string customName = 2; } message LoadBigInt { @@ -107,6 +109,12 @@ message BeginObjectLiteralGetter { message EndObjectLiteralGetter { } +message BeginObjectLiteralComputedGetter { +} + +message EndObjectLiteralComputedGetter { +} + message BeginObjectLiteralSetter { string propertyName = 1; } @@ -114,6 +122,12 @@ message BeginObjectLiteralSetter { message EndObjectLiteralSetter { } +message BeginObjectLiteralComputedSetter { +} + +message EndObjectLiteralComputedSetter { +} + message EndObjectLiteral { } @@ -129,122 +143,89 @@ 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 BeginClassInstanceGetter { - string propertyName = 1; -} - -message EndClassInstanceGetter { +message EndClassComputedMethod { } -message BeginClassInstanceSetter { +message BeginClassGetter { 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 BeginClassStaticInitializer { +message EndClassGetter { } -message EndClassStaticInitializer { -} - -message BeginClassStaticMethod { - string methodName = 1; - Parameters parameters = 2; +message BeginClassComputedGetter { + bool is_static = 1; } -message EndClassStaticMethod { +message EndClassComputedGetter { } -message BeginClassStaticComputedMethod { - Parameters parameters = 1; -} - -message EndClassStaticComputedMethod { -} - -message BeginClassStaticGetter { +message BeginClassSetter { string propertyName = 1; + bool is_static = 2; } -message EndClassStaticGetter { -} - -message BeginClassStaticSetter { - string propertyName = 1; +message EndClassSetter { } -message EndClassStaticSetter { +message BeginClassComputedSetter { + bool is_static = 1; } -message ClassAddPrivateInstanceProperty { - string propertyName = 1; - bool hasValue = 2; +message EndClassComputedSetter { } -message BeginClassPrivateInstanceMethod { - string methodName = 1; - Parameters parameters = 2; +message BeginClassStaticInitializer { } -message EndClassPrivateInstanceMethod { +message EndClassStaticInitializer { } -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 { @@ -884,7 +865,6 @@ message Constf64 { } message WasmReturn { - repeated WasmILType returnTypes = 1; } // We only serialize the wasm types as the rest would be overkill and are not needed. @@ -930,18 +910,16 @@ 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 { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; + int32 outputCount = 2; } message Wasmi32CompareOp { @@ -1147,19 +1125,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 { @@ -1174,13 +1143,12 @@ message WasmCallIndirect { } message WasmCallDirect { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; + int32 outputCount = 2; } message WasmReturnCallDirect { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmReturnCallIndirect { @@ -1238,21 +1206,19 @@ message WasmMemoryFill { } message WasmBeginBlock { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmEndBlock { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } message WasmBeginLoop { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmEndLoop { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } enum WasmCatchKind { @@ -1263,44 +1229,40 @@ enum WasmCatchKind { } message WasmBeginTryTable { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; - repeated WasmCatchKind catches = 3; + int32 parameterCount = 1; + repeated WasmCatchKind catches = 2; } message WasmEndTryTable { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } message WasmBeginTry { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmBeginCatchAll { - repeated WasmILType inputTypes = 1; + int32 blockOutputCount = 1; } message WasmBeginCatch { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 blockOutputCount = 1; + int32 labelParameterCount = 2; } message WasmEndTry { - repeated WasmILType outputTypes = 1; + int32 blockOutputCount = 1; } message WasmBeginTryDelegate { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmEndTryDelegate { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } message WasmThrow { - repeated WasmILType parameterTypes = 1; } message WasmThrowRef { @@ -1310,11 +1272,9 @@ message WasmRethrow { } message WasmDefineTag { - repeated WasmILType parameterTypes = 1; } message WasmBranch { - repeated WasmILType parameters = 1; } enum WasmBranchHint { @@ -1324,33 +1284,29 @@ enum WasmBranchHint { } message WasmBranchIf { - repeated WasmILType parameters = 1; WasmBranchHint hint = 2; } message WasmBranchTable { - repeated WasmILType parameters = 1; uint32 valueCount = 2; } message WasmReassign { - WasmILType variableType = 1; } message WasmBeginIf { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; bool inverted = 3; WasmBranchHint hint = 4; } message WasmBeginElse { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; + int32 outputCount = 2; } message WasmEndIf { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } message WasmNop { @@ -1503,6 +1459,16 @@ message WasmDefineSignatureType { repeated WasmILType outputTypes = 2; } +message WasmDefineAdHocSignatureType { + repeated WasmILType parameterTypes = 1; + repeated WasmILType outputTypes = 2; +} + +message WasmDefineAdHocModuleSignatureType { + repeated WasmILType parameterTypes = 1; + repeated WasmILType outputTypes = 2; +} + message WasmDefineArrayType { WasmILType elementType = 1; bool mutability = 2; @@ -1542,6 +1508,9 @@ message WasmArraySet { message WasmStructNewDefault { } +message WasmStructNew { +} + message WasmStructGet { int32 fieldIndex = 1; bool isSigned = 2; @@ -1558,7 +1527,19 @@ message WasmRefNull { message WasmRefIsNull { } +message WasmRefEq { +} + +message WasmRefTest { + WasmILType type = 1; +} + +message WasmRefCast { + WasmILType type = 1; +} + message WasmRefI31 { + bool isShared = 1; } message WasmI31Get { @@ -1691,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 bf4e21f82..a84249e86 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 { @@ -2721,6 +2609,134 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .createNamedAsyncDisposableVariable(newValue)} } + public var wasmDefineAdHocSignatureType: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType { + get { + if case .wasmDefineAdHocSignatureType(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmDefineAdHocSignatureType() + } + set {operation = .wasmDefineAdHocSignatureType(newValue)} + } + + public var wasmStructNew: Fuzzilli_Protobuf_WasmStructNew { + get { + if case .wasmStructNew(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmStructNew() + } + set {operation = .wasmStructNew(newValue)} + } + + public var wasmRefEq: Fuzzilli_Protobuf_WasmRefEq { + get { + if case .wasmRefEq(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmRefEq() + } + set {operation = .wasmRefEq(newValue)} + } + + public var wasmRefTest: Fuzzilli_Protobuf_WasmRefTest { + get { + if case .wasmRefTest(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmRefTest() + } + set {operation = .wasmRefTest(newValue)} + } + + public var wasmDefineAdHocModuleSignatureType: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType { + get { + if case .wasmDefineAdHocModuleSignatureType(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType() + } + set {operation = .wasmDefineAdHocModuleSignatureType(newValue)} + } + + public var wasmRefCast: Fuzzilli_Protobuf_WasmRefCast { + get { + if case .wasmRefCast(let v)? = operation {return v} + return Fuzzilli_Protobuf_WasmRefCast() + } + 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 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 { @@ -2757,36 +2773,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) @@ -3058,6 +3060,22 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmDefineSignatureType(Fuzzilli_Protobuf_WasmDefineSignatureType) case createNamedDisposableVariable(Fuzzilli_Protobuf_CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable) + case wasmDefineAdHocSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocSignatureType) + case wasmStructNew(Fuzzilli_Protobuf_WasmStructNew) + case wasmRefEq(Fuzzilli_Protobuf_WasmRefEq) + 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) + case beginBundleScript(Fuzzilli_Protobuf_BeginBundleScript) + case endBundleScript(Fuzzilli_Protobuf_EndBundleScript) } @@ -3070,29 +3088,34 @@ public struct Fuzzilli_Protobuf_Program: @unchecked Sendable { // methods supported on all messages. public var uuid: Data { - get {return _storage._uuid} + get {_storage._uuid} set {_uniqueStorage()._uuid = newValue} } public var code: [Fuzzilli_Protobuf_Instruction] { - get {return _storage._code} + get {_storage._code} set {_uniqueStorage()._code = newValue} } public var comments: Dictionary { - get {return _storage._comments} + get {_storage._comments} set {_uniqueStorage()._comments = newValue} } public var parent: Fuzzilli_Protobuf_Program { - get {return _storage._parent ?? Fuzzilli_Protobuf_Program()} + get {_storage._parent ?? Fuzzilli_Protobuf_Program()} set {_uniqueStorage()._parent = newValue} } /// Returns true if `parent` has been explicitly set. - public var hasParent: Bool {return _storage._parent != nil} + public var hasParent: Bool {_storage._parent != nil} /// 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}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") + 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() { @@ -3540,748 +3563,566 @@ 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 hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .updateElement(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateElement(v) - } - }() - case 79: try { - var v: Fuzzilli_Protobuf_DeleteElement? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .deleteElement(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteElement(v) - } - }() - case 80: try { - var v: Fuzzilli_Protobuf_ConfigureElement? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .configureElement(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureElement(v) - } - }() - case 81: try { - var v: Fuzzilli_Protobuf_GetComputedProperty? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .getComputedProperty(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getComputedProperty(v) - } - }() - case 82: try { - var v: Fuzzilli_Protobuf_SetComputedProperty? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .setComputedProperty(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setComputedProperty(v) - } - }() - case 83: try { - var v: Fuzzilli_Protobuf_UpdateComputedProperty? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .updateComputedProperty(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateComputedProperty(v) - } - }() - case 84: try { - var v: Fuzzilli_Protobuf_DeleteComputedProperty? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .deleteComputedProperty(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteComputedProperty(v) - } - }() - case 85: try { - var v: Fuzzilli_Protobuf_ConfigureComputedProperty? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .configureComputedProperty(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureComputedProperty(v) - } - }() - case 86: try { - var v: Fuzzilli_Protobuf_TypeOf? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .typeOf(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .typeOf(v) - } - }() - case 87: try { - var v: Fuzzilli_Protobuf_Void? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .void(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .void(v) - } - }() - case 88: try { - var v: Fuzzilli_Protobuf_TestInstanceOf? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .testInstanceOf(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .testInstanceOf(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 v: Fuzzilli_Protobuf_BeginArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true @@ -4293,7 +4134,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginArrowFunction(v) } }() - case 93: try { + case 79: try { var v: Fuzzilli_Protobuf_EndArrowFunction? var hadOneofValue = false if let current = self.operation { @@ -4306,7 +4147,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endArrowFunction(v) } }() - case 94: try { + case 80: try { var v: Fuzzilli_Protobuf_BeginGeneratorFunction? var hadOneofValue = false if let current = self.operation { @@ -4319,7 +4160,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginGeneratorFunction(v) } }() - case 95: try { + case 81: try { var v: Fuzzilli_Protobuf_EndGeneratorFunction? var hadOneofValue = false if let current = self.operation { @@ -4332,7 +4173,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endGeneratorFunction(v) } }() - case 96: try { + case 82: try { var v: Fuzzilli_Protobuf_BeginAsyncFunction? var hadOneofValue = false if let current = self.operation { @@ -4345,7 +4186,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginAsyncFunction(v) } }() - case 97: try { + case 83: try { var v: Fuzzilli_Protobuf_EndAsyncFunction? var hadOneofValue = false if let current = self.operation { @@ -4358,7 +4199,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endAsyncFunction(v) } }() - case 98: try { + case 84: try { var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { @@ -4371,7 +4212,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginAsyncArrowFunction(v) } }() - case 99: try { + case 85: try { var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { @@ -4384,7 +4225,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endAsyncArrowFunction(v) } }() - case 100: try { + case 86: try { var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { @@ -4397,7 +4238,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginAsyncGeneratorFunction(v) } }() - case 101: try { + case 87: try { var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { @@ -4410,7 +4251,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endAsyncGeneratorFunction(v) } }() - case 102: try { + case 88: try { var v: Fuzzilli_Protobuf_BeginConstructor? var hadOneofValue = false if let current = self.operation { @@ -4423,7 +4264,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginConstructor(v) } }() - case 103: try { + case 89: try { var v: Fuzzilli_Protobuf_EndConstructor? var hadOneofValue = false if let current = self.operation { @@ -4436,7 +4277,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 { @@ -4449,7 +4290,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 { @@ -4462,7 +4303,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 { @@ -4475,7 +4316,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 { @@ -4488,7 +4329,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 { @@ -4501,7 +4342,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 { @@ -4514,7 +4355,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 { @@ -4527,7 +4368,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 { @@ -4540,7 +4381,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 { @@ -4553,7 +4394,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 { @@ -4566,7 +4407,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 { @@ -4579,7 +4420,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 { @@ -4592,7 +4433,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 { @@ -4605,7 +4446,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 { @@ -4618,7 +4459,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 { @@ -4631,7 +4472,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 { @@ -4644,7 +4485,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 { @@ -4657,7 +4498,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 { @@ -4670,7 +4511,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 { @@ -4683,7 +4524,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 { @@ -4696,7 +4537,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 { @@ -4709,7 +4550,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 { @@ -4722,7 +4563,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 { @@ -4735,7 +4576,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 { @@ -4748,7 +4589,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 { @@ -4761,7 +4602,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 { @@ -4774,7 +4615,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 { @@ -4787,7 +4628,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 { @@ -4800,7 +4641,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 { @@ -4813,7 +4654,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 { @@ -4826,7 +4667,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 { @@ -4839,7 +4680,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 { @@ -4852,7 +4693,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 { @@ -4865,7 +4706,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 { @@ -4878,7 +4719,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 { @@ -4891,7 +4732,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 { @@ -4904,7 +4745,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 { @@ -4917,7 +4758,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 { @@ -4930,7 +4771,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 { @@ -4943,7 +4784,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 { @@ -4956,7 +4797,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 { @@ -4969,7 +4810,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 { @@ -4982,7 +4823,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 { @@ -4995,7 +4836,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 { @@ -5008,7 +4849,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 { @@ -5021,7 +4862,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 { @@ -5034,7 +4875,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 { @@ -5047,7 +4888,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 { @@ -5060,7 +4901,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 { @@ -5073,7 +4914,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 { @@ -5086,7 +4927,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 { @@ -5099,7 +4940,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 { @@ -5112,7 +4953,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 { @@ -5125,7 +4966,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 { @@ -5138,7 +4979,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 { @@ -5151,7 +4992,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 { @@ -5164,7 +5005,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 { @@ -5177,7 +5018,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 { @@ -5190,7 +5031,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 { @@ -5203,7 +5044,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 { @@ -5216,7 +5057,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 { @@ -5229,7 +5070,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 { @@ -5242,7 +5083,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 { @@ -5255,7 +5096,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 { @@ -5268,7 +5109,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 { @@ -5281,7 +5122,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 { @@ -5294,7 +5135,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 { @@ -5307,7 +5148,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 { @@ -5320,7 +5161,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 { @@ -5333,7 +5174,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 { @@ -5346,7 +5187,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 { @@ -5359,7 +5200,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 { @@ -5372,7 +5213,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 { @@ -5385,7 +5226,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 { @@ -5398,7 +5239,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 { @@ -5411,7 +5252,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 { @@ -5424,7 +5265,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 { @@ -5437,7 +5278,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 { @@ -5450,7 +5291,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 { @@ -5463,7 +5304,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 { @@ -5476,7 +5317,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 { @@ -5489,7 +5330,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 { @@ -5502,7 +5343,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 { @@ -5515,7 +5356,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 { @@ -5528,7 +5369,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 { @@ -5541,7 +5382,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 { @@ -5554,7 +5395,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 { @@ -5567,7 +5408,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 { @@ -5580,7 +5421,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 { @@ -5593,7 +5434,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 { @@ -5606,7 +5447,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 { @@ -5619,7 +5460,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 { @@ -5632,7 +5473,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 { @@ -5645,7 +5486,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 { @@ -5658,7 +5499,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 { @@ -5671,7 +5512,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 { @@ -5684,7 +5525,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 { @@ -5697,7 +5538,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 { @@ -5710,7 +5551,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 { @@ -5723,7 +5564,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 { @@ -5736,7 +5577,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 { @@ -5749,7 +5590,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 { @@ -5762,7 +5603,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 { @@ -5775,7 +5616,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 { @@ -5788,7 +5629,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 { @@ -5801,7 +5642,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 { @@ -5814,7 +5655,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 { @@ -5827,7 +5668,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 { @@ -5840,7 +5681,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 { @@ -5853,7 +5694,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 { @@ -5866,7 +5707,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 { @@ -5879,7 +5720,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 { @@ -5892,7 +5733,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 { @@ -5905,7 +5746,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 { @@ -5918,7 +5759,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 { @@ -5931,7 +5772,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 { @@ -5944,7 +5785,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 { @@ -5957,7 +5798,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 { @@ -5970,7 +5811,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 { @@ -5983,7 +5824,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 { @@ -5996,7 +5837,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 { @@ -6009,7 +5850,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 { @@ -6022,7 +5863,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 { @@ -6035,7 +5876,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 { @@ -6048,7 +5889,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 { @@ -6061,7 +5902,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 { @@ -6074,7 +5915,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 { @@ -6087,7 +5928,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 { @@ -6100,7 +5941,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 { @@ -6113,7 +5954,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 { @@ -6126,7 +5967,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 { @@ -6139,7 +5980,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 { @@ -6152,7 +5993,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 { @@ -6165,7 +6006,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 { @@ -6178,7 +6019,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 { @@ -6191,7 +6032,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 { @@ -6204,7 +6045,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 { @@ -6217,7 +6058,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 { @@ -6230,7 +6071,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 { @@ -6243,7 +6084,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 { @@ -6256,7 +6097,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 { @@ -6269,7 +6110,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 { @@ -6282,7 +6123,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 { @@ -6295,7 +6136,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 { @@ -6308,7 +6149,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 { @@ -6321,7 +6162,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 { @@ -6334,7 +6175,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 { @@ -6347,7 +6188,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 { @@ -6360,7 +6201,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 { @@ -6373,7 +6214,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 { @@ -6386,7 +6227,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 { @@ -6399,7 +6240,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 { @@ -6412,7 +6253,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 { @@ -6425,7 +6266,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 { @@ -6438,7 +6279,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 { @@ -6451,7 +6292,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 { @@ -6464,7 +6305,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 { @@ -6477,7 +6318,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 { @@ -6490,7 +6331,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 { @@ -6503,7 +6344,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 { @@ -6516,7 +6357,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 { @@ -6529,7 +6370,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 { @@ -6542,7 +6383,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 { @@ -6555,7 +6396,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 { @@ -6568,7 +6409,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 { @@ -6581,7 +6422,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 { @@ -6594,7 +6435,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 { @@ -6607,7 +6448,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 { @@ -6620,7 +6461,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 { @@ -6633,7 +6474,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 { @@ -6646,7 +6487,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 { @@ -6659,7 +6500,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 { @@ -6672,7 +6513,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 { @@ -6685,7 +6526,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 { @@ -6698,7 +6539,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 { @@ -6711,7 +6552,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 { @@ -6724,7 +6565,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 { @@ -6737,7 +6578,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 { @@ -6750,7 +6591,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 { @@ -6763,7 +6604,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 { @@ -6776,7 +6617,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 { @@ -6789,7 +6630,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 { @@ -6802,7 +6643,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 { @@ -6815,7 +6656,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 { @@ -6828,7 +6669,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 { @@ -6841,7 +6682,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 { @@ -6854,7 +6695,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 { @@ -6867,7 +6708,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 { @@ -6880,7 +6721,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 { @@ -6893,7 +6734,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 { @@ -6906,7 +6747,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 { @@ -6919,7 +6760,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 { @@ -6932,7 +6773,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 { @@ -6945,7 +6786,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 { @@ -6958,7 +6799,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 { @@ -6971,7 +6812,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 { @@ -6984,7 +6825,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 { @@ -6997,7 +6838,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 { @@ -7010,7 +6851,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 { @@ -7023,7 +6864,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 { @@ -7036,7 +6877,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 { @@ -7049,7 +6890,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 { @@ -7062,7 +6903,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 { @@ -7075,7 +6916,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 { @@ -7088,7 +6929,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 { @@ -7101,7 +6942,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 { @@ -7114,7 +6955,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 { @@ -7127,7 +6968,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 { @@ -7140,7 +6981,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 { @@ -7153,7 +6994,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 { @@ -7166,7 +7007,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 { @@ -7179,7 +7020,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 { @@ -7192,7 +7033,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 { @@ -7205,7 +7046,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 { @@ -7218,7 +7059,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 { @@ -7231,7 +7072,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 { @@ -7244,7 +7085,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 { @@ -7257,7 +7098,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 { @@ -7270,7 +7111,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 { @@ -7283,7 +7124,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 { @@ -7296,7 +7137,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 { @@ -7309,7 +7150,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 { @@ -7322,7 +7163,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 { @@ -7335,7 +7176,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 { @@ -7348,7 +7189,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 { @@ -7361,7 +7202,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 { @@ -7374,7 +7215,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 { @@ -7387,7 +7228,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 { @@ -7400,7 +7241,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 { @@ -7413,7 +7254,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 { @@ -7426,7 +7267,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 { @@ -7439,7 +7280,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 { @@ -7452,106 +7293,314 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedAsyncDisposableVariable(v) } }() - 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.inouts.isEmpty { - try visitor.visitPackedUInt32Field(value: self.inouts, fieldNumber: 1) - } - switch self.operation { - case .opIdx?: try { - guard case .opIdx(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) - }() - case .nop?: try { - guard case .nop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - }() - case .loadInteger?: try { - guard case .loadInteger(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - }() - case .loadBigInt?: try { - guard case .loadBigInt(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - }() - case .loadFloat?: try { - guard case .loadFloat(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) - }() - case .loadString?: try { - guard case .loadString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 7) - }() - case .loadBoolean?: try { - guard case .loadBoolean(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 8) - }() - case .loadUndefined?: try { - guard case .loadUndefined(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 9) - }() - case .loadNull?: try { - guard case .loadNull(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 10) - }() - case .loadThis?: try { - guard case .loadThis(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 11) - }() - case .loadArguments?: try { - guard case .loadArguments(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 12) - }() - case .createNamedVariable?: try { - guard case .createNamedVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 13) - }() - case .loadDisposableVariable?: try { - guard case .loadDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 14) - }() - case .loadAsyncDisposableVariable?: try { - guard case .loadAsyncDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 15) - }() - case .loadRegExp?: try { - guard case .loadRegExp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 16) - }() - case .beginObjectLiteral?: try { - guard case .beginObjectLiteral(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 17) - }() - case .objectLiteralAddProperty?: try { - guard case .objectLiteralAddProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 18) - }() - case .objectLiteralAddElement?: try { - guard case .objectLiteralAddElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 19) - }() - case .objectLiteralAddComputedProperty?: try { - guard case .objectLiteralAddComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 20) - }() - case .objectLiteralCopyProperties?: try { - guard case .objectLiteralCopyProperties(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 21) - }() - case .objectLiteralSetPrototype?: try { - guard case .objectLiteralSetPrototype(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 22) - }() - case .beginObjectLiteralMethod?: try { - guard case .beginObjectLiteralMethod(let v)? = self.operation else { preconditionFailure() } + case 322: try { + var v: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmDefineAdHocSignatureType(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .wasmDefineAdHocSignatureType(v) + } + }() + case 323: try { + var v: Fuzzilli_Protobuf_WasmStructNew? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmStructNew(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .wasmStructNew(v) + } + }() + case 324: try { + var v: Fuzzilli_Protobuf_WasmRefEq? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmRefEq(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .wasmRefEq(v) + } + }() + case 325: try { + var v: Fuzzilli_Protobuf_WasmRefTest? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmRefTest(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .wasmRefTest(v) + } + }() + case 326: try { + var v: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmDefineAdHocModuleSignatureType(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .wasmDefineAdHocModuleSignatureType(v) + } + }() + case 327: try { + var v: Fuzzilli_Protobuf_WasmRefCast? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .wasmRefCast(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + 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) + } + }() + 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 + } + } + } + + 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.inouts.isEmpty { + try visitor.visitPackedUInt32Field(value: self.inouts, fieldNumber: 1) + } + switch self.operation { + case .opIdx?: try { + guard case .opIdx(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) + }() + case .nop?: try { + guard case .nop(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + }() + case .loadInteger?: try { + guard case .loadInteger(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + }() + case .loadBigInt?: try { + guard case .loadBigInt(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + }() + case .loadFloat?: try { + guard case .loadFloat(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + }() + case .loadString?: try { + guard case .loadString(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 7) + }() + case .loadBoolean?: try { + guard case .loadBoolean(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 8) + }() + case .loadUndefined?: try { + guard case .loadUndefined(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 9) + }() + case .loadNull?: try { + guard case .loadNull(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + }() + case .loadThis?: try { + guard case .loadThis(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 11) + }() + case .loadArguments?: try { + guard case .loadArguments(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 12) + }() + case .createNamedVariable?: try { + guard case .createNamedVariable(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 13) + }() + case .loadDisposableVariable?: try { + guard case .loadDisposableVariable(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 14) + }() + case .loadAsyncDisposableVariable?: try { + guard case .loadAsyncDisposableVariable(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 15) + }() + case .loadRegExp?: try { + guard case .loadRegExp(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 16) + }() + case .beginObjectLiteral?: try { + guard case .beginObjectLiteral(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 17) + }() + case .objectLiteralAddProperty?: try { + guard case .objectLiteralAddProperty(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 18) + }() + case .objectLiteralAddElement?: try { + guard case .objectLiteralAddElement(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 19) + }() + case .objectLiteralAddComputedProperty?: try { + guard case .objectLiteralAddComputedProperty(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 20) + }() + case .objectLiteralCopyProperties?: try { + guard case .objectLiteralCopyProperties(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 21) + }() + case .objectLiteralSetPrototype?: try { + guard case .objectLiteralSetPrototype(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 22) + }() + case .beginObjectLiteralMethod?: try { + guard case .beginObjectLiteralMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 23) }() case .endObjectLiteralMethod?: try { @@ -7598,1210 +7647,1218 @@ 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: 321) + }() + case .wasmDefineAdHocSignatureType?: try { + guard case .wasmDefineAdHocSignatureType(let v)? = self.operation else { preconditionFailure() } + 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: 323) + }() + case .wasmRefEq?: try { + guard case .wasmRefEq(let v)? = self.operation else { preconditionFailure() } + 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: 325) + }() + case .wasmDefineAdHocModuleSignatureType?: try { + guard case .wasmDefineAdHocModuleSignatureType(let v)? = self.operation else { preconditionFailure() } + 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: 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 .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 0582386bf..1a7c830c6 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -58,307 +58,309 @@ 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; + 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; + BeginObjectLiteralComputedGetter beginObjectLiteralComputedGetter = 328; + EndObjectLiteralComputedGetter endObjectLiteralComputedGetter = 329; + BeginObjectLiteralComputedSetter beginObjectLiteralComputedSetter = 330; + EndObjectLiteralComputedSetter endObjectLiteralComputedSetter = 331; + BeginClassComputedGetter beginClassComputedGetter = 332; + 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 0c64d22da..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() {} @@ -77,106 +79,112 @@ public struct Fuzzilli_Protobuf_Statistics: @unchecked Sendable { //// The total number of samples produced. public var totalSamples: UInt64 { - get {return _storage._totalSamples} + get {_storage._totalSamples} set {_uniqueStorage()._totalSamples = newValue} } //// The number of valid samples produced. public var validSamples: UInt64 { - get {return _storage._validSamples} + get {_storage._validSamples} set {_uniqueStorage()._validSamples = newValue} } //// The number of intersting samples produced. public var interestingSamples: UInt64 { - get {return _storage._interestingSamples} + get {_storage._interestingSamples} set {_uniqueStorage()._interestingSamples = newValue} } //// The number of timed-out samples produced. public var timedOutSamples: UInt64 { - get {return _storage._timedOutSamples} + get {_storage._timedOutSamples} set {_uniqueStorage()._timedOutSamples = newValue} } //// The number of crashes found. public var crashingSamples: UInt64 { - get {return _storage._crashingSamples} + get {_storage._crashingSamples} set {_uniqueStorage()._crashingSamples = newValue} } //// The total number of program executions. public var totalExecs: UInt64 { - get {return _storage._totalExecs} + get {_storage._totalExecs} set {_uniqueStorage()._totalExecs = newValue} } //// The average size of the corpus of this node and its child nodes. public var avgCorpusSize: Double { - get {return _storage._avgCorpusSize} + get {_storage._avgCorpusSize} set {_uniqueStorage()._avgCorpusSize = newValue} } //// The average size of recently generated programs. public var avgProgramSize: Double { - get {return _storage._avgProgramSize} + get {_storage._avgProgramSize} set {_uniqueStorage()._avgProgramSize = newValue} } //// The average size of programs recently added to the corpus. public var avgCorpusProgramSize: Double { - get {return _storage._avgCorpusProgramSize} + get {_storage._avgCorpusProgramSize} set {_uniqueStorage()._avgCorpusProgramSize = newValue} } //// The average execution time of recently generated and successfully executed programs in seconds. public var avgExecutionTime: Double { - get {return _storage._avgExecutionTime} + get {_storage._avgExecutionTime} set {_uniqueStorage()._avgExecutionTime = newValue} } //// The current number of executions per second. public var execsPerSecond: Double { - get {return _storage._execsPerSecond} + get {_storage._execsPerSecond} set {_uniqueStorage()._execsPerSecond = newValue} } //// The average fraction of the total time that is not spent executing programs in the target engine. public var fuzzerOverhead: Double { - get {return _storage._fuzzerOverhead} + get {_storage._fuzzerOverhead} set {_uniqueStorage()._fuzzerOverhead = newValue} } //// The average fraction of recent executions spent on minimization. public var minimizationOverhead: Double { - get {return _storage._minimizationOverhead} + get {_storage._minimizationOverhead} set {_uniqueStorage()._minimizationOverhead = newValue} } //// The number of child nodes connected directly or indirectly to this instance, i.e. the size of the (sub-)tree rooted at this instance. public var numChildNodes: UInt64 { - get {return _storage._numChildNodes} + get {_storage._numChildNodes} set {_uniqueStorage()._numChildNodes = newValue} } //// The percentage of edges covered if doing coverage-guided fuzzing. public var coverage: Double { - get {return _storage._coverage} + get {_storage._coverage} set {_uniqueStorage()._coverage = newValue} } //// The correctness rate of recently generated programs (number of valid programs divided by number of generated programs). public var correctnessRate: Double { - get {return _storage._correctnessRate} + get {_storage._correctnessRate} set {_uniqueStorage()._correctnessRate = newValue} } //// The timeout rate of recently generated programs (number of timeouts divided by number of generated programs). public var timeoutRate: Double { - get {return _storage._timeoutRate} + get {_storage._timeoutRate} set {_uniqueStorage()._timeoutRate = newValue} } + //// The number of programs resulting in valid differential produced. + public var differentialSamples: UInt64 { + get {_storage._differentialSamples} + set {_uniqueStorage()._differentialSamples = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -235,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() { @@ -246,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 } } @@ -261,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) } @@ -268,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 } @@ -275,7 +288,7 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Statistics" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}totalSamples\0\u{1}validSamples\0\u{1}interestingSamples\0\u{1}timedOutSamples\0\u{1}crashingSamples\0\u{1}totalExecs\0\u{1}avgCorpusSize\0\u{1}avgProgramSize\0\u{1}avgCorpusProgramSize\0\u{1}avgExecutionTime\0\u{1}execsPerSecond\0\u{1}fuzzerOverhead\0\u{1}minimizationOverhead\0\u{1}numChildNodes\0\u{1}coverage\0\u{1}correctnessRate\0\u{1}timeoutRate\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}totalSamples\0\u{1}validSamples\0\u{1}interestingSamples\0\u{1}timedOutSamples\0\u{1}crashingSamples\0\u{1}totalExecs\0\u{1}avgCorpusSize\0\u{1}avgProgramSize\0\u{1}avgCorpusProgramSize\0\u{1}avgExecutionTime\0\u{1}execsPerSecond\0\u{1}fuzzerOverhead\0\u{1}minimizationOverhead\0\u{1}numChildNodes\0\u{1}coverage\0\u{1}correctnessRate\0\u{1}timeoutRate\0\u{1}differentialSamples\0") fileprivate class _StorageClass { var _totalSamples: UInt64 = 0 @@ -295,6 +308,7 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me var _coverage: Double = 0 var _correctnessRate: Double = 0 var _timeoutRate: Double = 0 + var _differentialSamples: UInt64 = 0 // 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. @@ -322,6 +336,7 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me _coverage = source._coverage _correctnessRate = source._correctnessRate _timeoutRate = source._timeoutRate + _differentialSamples = source._differentialSamples } } @@ -357,6 +372,7 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me case 15: try { try decoder.decodeSingularDoubleField(value: &_storage._coverage) }() case 16: try { try decoder.decodeSingularDoubleField(value: &_storage._correctnessRate) }() case 17: try { try decoder.decodeSingularDoubleField(value: &_storage._timeoutRate) }() + case 18: try { try decoder.decodeSingularUInt64Field(value: &_storage._differentialSamples) }() default: break } } @@ -416,6 +432,9 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me if _storage._timeoutRate.bitPattern != 0 { try visitor.visitSingularDoubleField(value: _storage._timeoutRate, fieldNumber: 17) } + if _storage._differentialSamples != 0 { + try visitor.visitSingularUInt64Field(value: _storage._differentialSamples, fieldNumber: 18) + } } try unknownFields.traverse(visitor: &visitor) } @@ -442,6 +461,7 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me if _storage._coverage != rhs_storage._coverage {return false} if _storage._correctnessRate != rhs_storage._correctnessRate {return false} if _storage._timeoutRate != rhs_storage._timeoutRate {return false} + if _storage._differentialSamples != rhs_storage._differentialSamples {return false} return true } if !storagesAreEqual {return false} diff --git a/Sources/Fuzzilli/Protobuf/sync.proto b/Sources/Fuzzilli/Protobuf/sync.proto index e806773a6..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 { @@ -82,4 +83,7 @@ message Statistics { /// The timeout rate of recently generated programs (number of timeouts divided by number of generated programs). double timeoutRate = 17; + + /// The number of programs resulting in valid differential produced. + uint64 differentialSamples = 18; } diff --git a/Sources/Fuzzilli/Util/Arguments.swift b/Sources/Fuzzilli/Util/Arguments.swift index fcea3106a..0a05f294a 100644 --- a/Sources/Fuzzilli/Util/Arguments.swift +++ b/Sources/Fuzzilli/Util/Arguments.swift @@ -107,7 +107,9 @@ public class Arguments { optionalArguments[name] = value } - return Arguments(programName: args[0], positionalArguments: positionalArguments, optionalArguments: optionalArguments) + return Arguments( + programName: args[0], positionalArguments: positionalArguments, + optionalArguments: optionalArguments) } /// Parses a hostname and port from a string of the format "hostname:port". diff --git a/Sources/Fuzzilli/Util/CInterop.swift b/Sources/Fuzzilli/Util/CInterop.swift index 4b67c5948..e7961f112 100644 --- a/Sources/Fuzzilli/Util/CInterop.swift +++ b/Sources/Fuzzilli/Util/CInterop.swift @@ -17,18 +17,18 @@ import Foundation func convertToCArray(_ array: [String]) -> 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() + let outputData = OutputBuffer() + outputPipe.fileHandleForReading.readabilityHandler = { handle in + outputData.append(handle.availableData) + } + // 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() @@ -116,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) */ } } @@ -138,19 +189,13 @@ public class JavaScriptExecutor { try FileManager.default.removeItem(at: url) // Fetch and return the output. - var output = "" - if let data = String(data: outputPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) { - output = data - } else { - output = "Process output is not valid UTF-8" - } - var error = "" - if let data = String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) { - error = data - } else { - error = "Process stderr is not valid UTF-8" - } - var outcome: Result.Outcome + var output = + String(data: outputData.currentData, encoding: .utf8) + ?? "Process output is not valid UTF-8" + let error = + String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + ?? "Process stderr is not valid UTF-8" + let outcome: Result.Outcome if timedOut { outcome = .timedOut output += "\nError: Timed out" @@ -166,6 +211,10 @@ public class JavaScriptExecutor { var directories = pathVar.split(separator: ":") // Also append the homebrew binary path since it may not be in $PATH, especially inside XCode. directories.append("/opt/homebrew/bin") + // Append the CWD to enable bundling node.js from where the script + // is called. + directories.append( + String.SubSequence(FileManager.default.currentDirectoryPath)) for directory in directories { let path = String(directory + "/node") if FileManager.default.isExecutableFile(atPath: path) { @@ -183,22 +232,22 @@ public class JavaScriptExecutor { /// The Result of a JavaScript Execution, the exit code and any associated output. public struct Result { - enum Outcome: Equatable { + public enum Outcome: Equatable { case terminated(status: Int32) case timedOut } - let outcome: Outcome - let output: String - let error: String + public let outcome: Outcome + public let output: String + public let error: String - var isSuccess: Bool { + public var isSuccess: Bool { return outcome == .terminated(status: 0) } - var isFailure: Bool { + public var isFailure: Bool { return !isSuccess } - var isTimeOut: Bool { + public var isTimeOut: Bool { return outcome == .timedOut } } diff --git a/Sources/Fuzzilli/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift index 2f9558208..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,32 +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, - 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)") } @@ -150,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/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift deleted file mode 100644 index 91ff6d8ea..000000000 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright 2023 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 Fuzzilli - - -// A post-processor that inserts calls to the `corrupt` function (defined in the prefix below) into the generated samples. -fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { - func process(_ program: Fuzzilli.Program, for fuzzer: Fuzzer) -> Fuzzilli.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 - // generated program might hamper that. - if probability(0.5) { return program } - - let b = fuzzer.makeBuilder(forMutating: program) - - func corruptSomething() { - // 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 } - let numCorruptions = Int.random(in: 1...3) - for _ in 0.. 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:symbolize=false:redzone=128", "UBSAN_OPTIONS" : "abort_on_error=1:symbolize=false:redzone=128"], - - maxExecsBeforeRespawn: 1000, - - // ASan builds are slower, so we use a larger timeout. - timeout: Timeout.interval(500, 1200), - - codePrefix: """ - // - // BEGIN FUZZER GENERATED CODE - // - - """, - - codeSuffix: """ - - // - // BEGIN FUZZER HELPER CODE - // - - // Corrupt the given object in a deterministic fashion (when using the same seed) and log the steps being performed. - function corrupt(obj, seed) { - // In general, in this function memory contents is represented as (unsigned) BigInt, everything else (addresses, offsets, etc.) are Numbers. - - function assert(c) { - if (!c) { - throw new Error("Assertion in the in-sandbox-corruption API failed!"); - } - } - - 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; - - // 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); - } - - read32(addr) { - return BigInt(this.dataView.getUint32(addr, true)); - } - - write32(addr, value) { - this.dataView.setUint32(addr, Number(value), true); - } - - read16(addr) { - return BigInt(this.dataView.getUint16(addr, true)); - } - - write16(addr, value) { - this.dataView.setUint16(addr, Number(value), true); - } - - read8(addr) { - return BigInt(this.dataView.getUint8(addr)); - } - - write8(addr, value) { - this.dataView.setUint8(addr, Number(value)); - } - - 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); - } - 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 this.memory_corruption_worker === 'undefined') { - // Define as non-configurable and non-enumerable property. - let worker = new Worker(workerFunc, {type: 'function'}); - Object.defineProperty(this, 'memory_corruption_worker', {value: worker}); - } - - // 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; - return this.x; - } - - randomBigInt() { - return BigInt(this.randomInt()); - } - - randomIntBelow(n) { - return Math.floor(this.randomFloat() * n); - } - - randomBigIntBelow(n) { - return BigInt(this.randomIntBelow(Number(n))); - } - - randomBigIntInHalfOpenRange(lower, upper) { - assert(upper > lower); - let diff = upper - lower; - return lower + this.randomBigIntBelow(diff); - } - - randomFloat() { - return this.randomInt() / this.m; - } - - probability(p) { - return this.randomFloat() < p; - } - - randomElement(array) { - assert(array.length > 0); - let randomIndex = this.randomIntBelow(array.length) - return array[randomIndex]; - } - } - - // Helper class implementing the various binary mutations. - class Mutator { - rng; - - constructor(rng) { - this.rng = rng; - } - - mutate(value, numBits) { - assert(numBits <= 32); - let allMutations = [this.#mutateBitflip, this.#mutateIncrement, this.#mutateReplace]; - let mutate = this.rng.randomElement(allMutations); - return mutate.call(this, value, BigInt(numBits)); - } - - #mutateBitflip(value, numBits) { - let bitPosition = this.rng.randomBigIntBelow(numBits); - let bit = 1n << bitPosition; - return value ^ bit; - } - - #mutateIncrement(value, numBits) { - let increment = this.#generateRandomBigInt(numBits); - if (increment == 0n) increment = 1n; - return (value + increment) & ((1n << numBits) - 1n); - - } - - #mutateReplace(value, numBits) { - return this.#generateRandomBigInt(numBits); - } - - #generateRandomBigInt(numBits) { - // Generate a random integer, giving uniform weight to each order of magnitude (power-of-two). - // In other words, this function is equally likely to generate an integer in the range [n, 2n) or [2n, 4n). - let magnitude = this.rng.randomBigIntBelow(numBits + 1n); // Between [0, numBits] - let upper = 1n << magnitude; - let lower = upper >> 1n; - return this.rng.randomBigIntInHalfOpenRange(lower, upper); - } - } - - // 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 integer taken from the rng (which - // behaves deterministically). Note that we always take the first object if there are multiple object with the same instance - // type. For finding later neighbors, we rely on the |corrupt| logic to recursively pick neighbor objects. - function findRandomNeighborObject(addr, rng) { - 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; - } - - let query = rng.randomInt() & 0xffff; - let currentWinner = addr; - let currentBest = kUint16Max; - - for (let i = 0; i < N; i++) { - addr += Sandbox.getSizeOfObjectAt(addr); - let typeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); - if (typeId == kUnknownInstanceId) { - // We found a corrupted object or went past the end of a page. No point in searching any further. - break; - } - let hash = hash16(typeId); - let score = Math.abs(hash - query); - if (score < currentBest) { - currentBest = score; - currentWinner = addr; - } - } - - return currentWinner; - } - - // 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 size = 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(size).fill("a").join(""); - let destination = Sandbox.getAddressOf(placeholder); - memory.copyTagged(source, destination, size); - return destination; - } - - // Helper function implementing the object corruption logic. - function corruptObjectAt(addr, rng, depth) { - let indent = " ".repeat(depth + 1); - if (depth >= 10) { - print(indent + "Too much recursion, bailing out."); - return; - } - - // We cannot corrupt read-only objects (or any objects referenced from them, as they must also be read-only). - // This is simply an optimization, otherwise we would crash during the memory write below. - if (!Sandbox.isWritableObjectAt(addr)) { - print(indent + "Not corrupting read-only object"); - return; - } - - let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); - print(indent + "Corrupting object at 0x" + addr.toString(16) + " of type " + instanceType); - - // Some of the time, find a neighbor object to corrupt instead. - // This allows the fuzzer to discover and corrupt objects that are not directly referenced from a visible JavaScript variable. - if (rng.probability(0.25)) { - let newAddr = findRandomNeighborObject(addr, rng); - print(indent + "Recursively corrupting neighboring object at offset " + (newAddr - addr)); - return corruptObjectAt(newAddr, rng, depth + 1); - } - - // Determine a random field to corrupt. - let size = Sandbox.getSizeOfObjectAt(addr); - let offset = (rng.randomInt() % size) & kOffsetAlignmentMask; - - // Check if the field currently contains a pointer to another object. In that case, (most of the time) corrupt that other object instead. - let oldValue = memory.read32(addr + offset); - let isLikelyPointer = (oldValue & kHeapObjectTag) == kHeapObjectTag; - if (isLikelyPointer && rng.probability(0.75)) { - let newAddr = Number(oldValue & ~kHeapObjectTagMask); - if (Sandbox.isValidObjectAt(newAddr)) { - print(indent + "Recursively corrupting object referenced through pointer at offset " + offset); - if (!Sandbox.isWritableObjectAt(newAddr)) { - // We cannot corrupt the referenced object, so instead we create a copy of it and corrupt that instead. - newAddr = copyObjectAt(newAddr); - memory.write32(addr + offset, BigInt(newAddr) | kHeapObjectTag); - print(indent + "Referenced object is in read-only memory. Creating and corrupting a copy instead"); - } - return corruptObjectAt(newAddr, rng, depth + 1); - } - } - - // Finally, corrupt the object! - let numBitsToCorrupt = rng.randomElement([8, 16, 32]); - let mutator = new Mutator(rng); - let newValue; - switch (numBitsToCorrupt) { - case 8: - offset += rng.randomIntBelow(4); - oldValue = memory.read8(addr + offset); - newValue = mutator.mutate(oldValue, 8); - memory.write8(addr + offset, newValue); - break; - case 16: - offset += rng.randomIntBelow(2) * 2; - oldValue = memory.read16(addr + offset); - newValue = mutator.mutate(oldValue, 16); - memory.write16(addr + offset, newValue); - break; - case 32: - oldValue = memory.read32(addr + offset); - newValue = mutator.mutate(oldValue, 32); - memory.write32(addr + offset, newValue); - break; - } - - assert(oldValue >= 0 && oldValue < (1n << BigInt(numBitsToCorrupt))); - assert(newValue >= 0 && newValue < (1n << BigInt(numBitsToCorrupt))); - - print(indent + "Corrupted " + numBitsToCorrupt + "-bit field at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); - - // With low probability, keep flipping this value between the old and new value on a background worker thread. - if (rng.probability(0.10)) { - print(indent + "Will keep flipping this field between old and new value on background worker"); - this.memory_corruption_worker.postMessage({address: addr + offset, valueA: Number(oldValue), valueB: Number(newValue), size: numBitsToCorrupt}); - } - } - - let addr; - try { - addr = Sandbox.getAddressOf(obj); - } catch (e) { - // Presumably, |obj| is a Smi, not a HeapObject. - return; - } - - print("Corrupting memory starting from object at 0x" + addr.toString(16) + " with RNG seed " + seed); - corruptObjectAt(addr, new RNG(seed), 0); - } - """, - - ecmaVersion: ECMAScriptVersion.es6, - - startupTests: [ - // This makes sure that the fuzzilli builtin exists. - ("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed), - // This makes sure that the memory corruption api is available. - ("Sandbox.getAddressOf([1, 2, 3])", .shouldSucceed), - // This makes sure that the |corrupt| function is available and working. It whould not corrupt anything as it's passed an object in read-only space ('undefined'). - ("corrupt(undefined, 42);", .shouldSucceed), - // This triggers a DCHECK failure, which should be ignored, and execution should continue. - ("fuzzilli('FUZZILLI_CRASH', 2)", .shouldSucceed), - // This checks that we do not have DEBUG defined, and execution should continue. - ("fuzzilli('FUZZILLI_CRASH', 8)", .shouldSucceed), - - // Crashes that indicate a sandbox violation should be detected. - // This should crash with a wild write. - ("fuzzilli('FUZZILLI_CRASH', 3)", .shouldCrash), - // This should crash with an ASan-detectable use-after-free. - ("fuzzilli('FUZZILLI_CRASH', 4)", .shouldCrash), - // This should crash with an ASan-detectable out-of-bounds write. - ("fuzzilli('FUZZILLI_CRASH', 6)", .shouldCrash), - - // Crashes that are not sandbox violations and so should be filtered out by the crash filter. - // This triggers an IMMEDIATE_CRASH. - ("fuzzilli('FUZZILLI_CRASH', 0)", .shouldNotCrash), - // This triggers a CHECK failure. - ("fuzzilli('FUZZILLI_CRASH', 1)", .shouldNotCrash), - // This triggers a std::vector OOB access that should be caught by the libc++ hardening. - ("fuzzilli('FUZZILLI_CRASH', 5)", .shouldNotCrash), - ], - - additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (V8GcGenerator, 10), - (WasmStructGenerator, 5), - (WasmArrayGenerator, 5), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 5), - ], - - additionalProgramTemplates: WeightedList([ - ]), - - disabledCodeGenerators: [], - - disabledMutators: [], - - additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .object(), - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), - ], - - additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], - - additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], - - optionalPostProcessor: SandboxFuzzingPostProcessor() -) - diff --git a/Sources/FuzzilliCli/Profiles/XSProfile.swift b/Sources/FuzzilliCli/Profiles/XSProfile.swift deleted file mode 100644 index 1cb64c0f1..000000000 --- a/Sources/FuzzilliCli/Profiles/XSProfile.swift +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2019-2024 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 Fuzzilli - -fileprivate 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.callFunction(f, withArgs: arguments) - b.unary(.PostInc, index) - let result = b.callFunction(gc, withArgs: [index]) - b.buildIf(result) { - b.loopBreak() - } - } -} - -fileprivate 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 memoryFail = b.createNamedVariable(forBuiltin: "memoryFail") - 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.callFunction(f, withArgs: arguments) - b.unary(.PostInc, index) - b.callFunction(memoryFail, withArgs: [index]) - } -} - -fileprivate let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { b, obj in - let harden = b.createNamedVariable(forBuiltin: "harden") - - if probability(0.05) { - let lockdown = b.createNamedVariable(forBuiltin: "lockdown") - b.callFunction(lockdown) - } - b.callFunction(harden, withArgs: [obj]) -} - -fileprivate let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in - let moduleSourceConstructor = b.createNamedVariable(forBuiltin: "ModuleSource") - - let code = b.buildCodeString() { - b.build(n: 5) - } - - b.construct(moduleSourceConstructor, withArgs: [code]) -} - -fileprivate 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 moduleMap = [String: Variable]() - var options = [String: Variable]() - - for _ in 0.. '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" - ] - - let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - let (pattern, flags) = b.randomRegExpPatternAndFlags() - let regExpVar = b.loadRegExp(pattern, flags) - - let lastIndex = chooseUniform(from: lastIndices) - let lastIndexString = b.loadString(lastIndex) - - b.setProperty("lastIndex", of: regExpVar, to: lastIndexString) - - let subjectVar: Variable - - if probability(0.1) { - subjectVar = b.loadString(twoByteSubjectString) - } else { - subjectVar = b.loadString(b.randomString()) - } - - 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(resultVar, to: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: 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(resultVar, to: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: 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(resultVar, to: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) - }) - }, catchBody: { _ in - }) - - b.build(n: 7) - - b.doReturn(resultVar) - } - - b.callFunction(f) - - b.build(n: 15) -} - -public extension ILType { - /// Type of a JavaScript Compartment object. - 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: []) - - 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: []) -} - -/// Object group modelling JavaScript compartments. -let jsCompartments = ObjectGroup( - name: "Compartment", - instanceType: .jsCompartment, - properties: [ - "globalThis" : .object() - ], - methods: [ //@@ import/importNow can accept more than strings - "import" : [.string] => .jsPromise, - "importNow" : [.string] => .jsAnything, - // "module" : [.opt(.string)] => .object(), (currently unavailable) - "evaluate" : [.string] => .jsAnything, - ] -) - -let jsCompartmentConstructor = ObjectGroup( - name: "CompartmentConstructor", - instanceType: .jsCompartmentConstructor, - properties: [ - "prototype" : .object() - ], - methods: [:] -) - -/// Object group modelling JavaScript ModuleSources. -let jsModuleSources = ObjectGroup( - name: "ModuleSource", - instanceType: .jsModuleSource, - properties: [ - "bindings" : .object(), - "needsImport" : .object(), - "needsImportMeta" : .object(), - ], - methods: [:] -) - -let jsModuleSourceConstructor = ObjectGroup( - name: "ModuleSourceConstructor", - instanceType: .jsModuleSourceConstructor, - properties: [ - "prototype" : .object() - ], - methods: [:] -) - -let xsProfile = Profile( - processArgs: { randomize in - ["-f"] - }, - - 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(); - """, - - ecmaVersion: ECMAScriptVersion.es6, - - startupTests: [ - // Check that the fuzzilli integration is available. - ("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed), - - // Check that common crash types are detected. - ("fuzzilli('FUZZILLI_CRASH', 0)", .shouldCrash), - ("fuzzilli('FUZZILLI_CRASH', 1)", .shouldCrash), - ("fuzzilli('FUZZILLI_CRASH', 2)", .shouldCrash), - ], - - additionalCodeGenerators: [ - (StressXSMemoryFail, 5), - (StressXSGC, 5), - (HardenGenerator, 5), - (CompartmentGenerator, 5), - (CompartmentEvaluateGenerator, 5), - (UnicodeStringGenerator, 2), - (ModuleSourceGenerator, 3), - ], - - additionalProgramTemplates: WeightedList([ - (RegExpFuzzer, 1), - ]), - - disabledCodeGenerators: [], - - disabledMutators: [], - - additionalBuiltins: [ - "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()) - ], - - additionalObjectGroups: [jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor], - - additionalEnumerations: [], - - optionalPostProcessor: nil -) diff --git a/Sources/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift index 1bb5f1c84..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,22 @@ 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" + ) + } + } + + fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { differential in + if differential.isUnique { + print("########## Unique Differential Found ##########") + print(fuzzer.lifter.lift(differential.program, withOptions: .includeComments)) } } @@ -67,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 -----------") @@ -118,36 +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") } - 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) - 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) - """) + 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) + """) } private func formatTimeInterval(_ interval: TimeInterval) -> String { @@ -159,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 10612275b..ccc1a60c3 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -21,88 +21,92 @@ 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). + --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). + --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. + --bundle : Generate bundles containing multiple JS scripts and modules + + """) exit(0) } @@ -125,7 +129,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 @@ -139,6 +145,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") @@ -157,14 +164,16 @@ 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 +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 +209,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 +234,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 +254,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 +272,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 +288,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 +334,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 @@ -328,6 +352,10 @@ if args.unusedOptionals.count > 0 { configError("Invalid arguments: \(args.unusedOptionals)") } +if profile.isDifferential && storagePath == nil { + configError("Differential fuzzing mode requires storage path") +} + // Initialize the logger such that we can print to the screen. let logger = Logger(withLabel: "Cli") @@ -343,12 +371,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 { @@ -377,7 +405,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!") } @@ -404,39 +433,72 @@ 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) + // TODO(mliedtke): The flag should be controllable via the profile. + + (configuration.generateBundle ? ["--bundle"] : []) + return REPRL( + executable: jsShellPath, + processArguments: finalArgs, + processEnvironment: profile.processEnv, + maxExecsBeforeRespawn: profile.maxExecsBeforeRespawn + ) + } + // A script runner to execute JavaScript code in an instrumented JS engine. - let runner = REPRL(executable: jsShellPath, processArguments: jsShellArguments, processEnvironment: profile.processEnv, maxExecsBeforeRespawn: profile.maxExecsBeforeRespawn) + let runner = createRunner(jsShellArguments, false) + + // A script runner used to verify that the samples are indeed differential samples. + let referenceRunner: REPRL? = { + guard profile.isDifferential, let refArgs = profile.processArgsReference else { + return nil + } + return createRunner(refArgs, true) + }() /// 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), - (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. @@ -457,7 +519,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) } @@ -472,7 +535,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) } @@ -487,23 +552,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) @@ -512,9 +586,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") } @@ -523,31 +600,39 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let minimizer = Minimizer() // Construct the fuzzer instance. - return Fuzzer(configuration: configuration, - scriptRunner: runner, - 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) +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, + generateBundle: generateBundle, + storagePath: storagePath, + corpusGenerationIterations: corpusGenerationIterations, + forDifferentialFuzzing: forDifferentialFuzzing, + instanceId: 0, + dumplingEnabled: profile.isDifferential) let fuzzer = makeFuzzer(with: mainConfig) @@ -581,12 +666,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) @@ -598,10 +684,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 @@ -611,22 +700,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. @@ -641,6 +740,7 @@ fuzzer.sync { // Resume a previous fuzzing session ... if resume, let path = storagePath { + let start = Date() var corpus = loadCorpus(from: path + "/old_corpus") logger.info("Scheduling import of \(corpus.count) programs from previous fuzzing run.") @@ -650,6 +750,13 @@ fuzzer.sync { fuzzer.registerEventListener(for: fuzzer.events.CorpusImportComplete) { // Delete the old corpus directory as soon as the corpus import is complete. 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))." + ) } fuzzer.scheduleCorpusImport(corpus, importMode: .interestingOnly(shouldMinimize: false)) // We assume that the programs are already minimized @@ -658,11 +765,24 @@ fuzzer.sync { // ... or import an existing corpus. if let path = corpusImportPath { assert(!resume) + let start = Date() let corpus = loadCorpus(from: path) 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))." + ) + } + fuzzer.scheduleCorpusImport(corpus, importMode: corpusImportMode) } @@ -674,21 +794,27 @@ fuzzer.sync { fuzzer.start(runUntil: exitCondition) } -// Add thread worker instances if requested -// Worker instances use a slightly different configuration, mostly just a lower log level. -let workerConfig = Configuration(arguments: CommandLine.arguments, - timeout: timeout.maxTimeout(), - logLevel: .warning, - startupTests: profile.startupTests, - minimizationLimit: minimizationLimit, - enableDiagnostics: false, - enableInspection: inspect, - staticCorpus: staticCorpus, - tag: tag, - isWasmEnabled: enableWasm, - storagePath: storagePath) - -for _ in 1.. Never { + print(msg) + exit(-1) +} + +let args = Arguments.parse(from: CommandLine.arguments) + +let helpRequested = args["-h"] != nil || args["--help"] != nil +if helpRequested || 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). + --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)" + ) +} + +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); + } + + // 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: {} + }; + + flatGraph[currentId] = node; + + if (!isObjectOrFunction) return currentId; + if (currentDepth >= maxDepth) 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; + } + + 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); + })(); + """ + +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 jsonString = result.output + +struct PropertyReference: Codable { + let id: Int + let isGetter: Bool +} + +struct JSPropertyNode: Decodable { + let type: String + let properties: [String: PropertyReference] +} + +let data = jsonString.data(using: .utf8)! +let graph: [Int: JSPropertyNode] +do { + graph = try JSONDecoder().decode([Int: JSPropertyNode].self, from: data) +} catch { + fatalError("DECODE ERROR: \(error)") +} + +var visited = Set() +var missingBuiltins = [String]() +var potentiallyBroken = [String]() + +func checkNode(_ nodeId: Int, path: [String]) { + if visited.contains(nodeId) { return } + visited.insert(nodeId) + + guard let node = graph[nodeId] else { return } + // Calculate the IL type for the current object. + var type = path.first.map(jsEnvironment.type(ofBuiltin:)) + if type != nil { + for propertyName in path.dropFirst() { + type = jsEnvironment.type(ofProperty: propertyName, on: type!) + } + } + + 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" + } + for (prop, propertyRef) in propertyData { + let (childId, isGetter) = (propertyRef.id, propertyRef.isGetter) + + // Skip any `*.prototype.` if is a getter. These getters are meant to + // be used on an instance of the given object, registering them on the original prototype + // object doesn't help Fuzzilli in generating interesting programs. + if path.last == "prototype" && isGetter { + continue + } + + var newPath = path + 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 + if isExcluded { + continue + } + + let isRegistered: Bool + if let type { + isRegistered = jsEnvironment.type(ofProperty: prop, on: type) != .jsAnything + } else { + assert(path.isEmpty) + isRegistered = jsEnvironment.hasBuiltin(prop) + } + + // Some properties exist but aren't "accessible", e.g. a lot of getters exist on the + // prototype but they can only be called on a receiver, e.g. + // DisposableStack.prototype.disposed. + let isAccessible = graph[childId]?.type != "error" + + if !isRegistered && isAccessible { + missingBuiltins.append(pathString) + } else if isRegistered && !isAccessible { + potentiallyBroken.append(pathString) + } + + checkNode(childId, path: newPath) + } +} + +checkNode(0, path: []) +print(missingBuiltins.sorted().joined(separator: "\n")) +if !potentiallyBroken.isEmpty { + print("\nPotentially inaccessible but registered builtins: ") + print(potentiallyBroken.sorted().joined(separator: "\n")) +} 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 new file mode 100644 index 000000000..2bf9dca17 --- /dev/null +++ b/Sources/RelateTool/main.swift @@ -0,0 +1,115 @@ +// 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 +import Fuzzilli + +public struct V8DifferentialConfig { + public static let commonArgs: [String] = [ + "--expose-gc", + "--omit-quit", + "--allow-natives-for-differential-fuzzing", + "--fuzzing", + "--future", + "--harmony", + "--predictable", + "--trace", + "--print-bytecode", + "--correctness-fuzzer-suppressions", + "--no-lazy-feedback-allocation", + ] + + public static let differentialArgs: [String] = [ + "--no-sparkplug", + "--jit-fuzzing", + "--maglev-dumping", + "--turbofan-dumping", + "--turbofan-dumping-print-deopt-frames", + ] + + public static let referenceArgs: [String] = [ + "--no-turbofan", + "--no-maglev", + "--sparkplug-dumping", + "--interpreter-dumping", + ] +} + +struct Relater { + let d8Path: String + let pocPath: String + let dumpFilePath: String + + private func runV8(args: [String]) throws { + let process = Process() + process.executableURL = URL(fileURLWithPath: d8Path) + process.arguments = args + [pocPath] + + let pipe = Pipe() + process.standardOutput = pipe + process.standardError = pipe + + try process.run() + process.waitUntilExit() + } + + private func readDumpFile() throws -> String { + return try String(contentsOfFile: dumpFilePath, encoding: .utf8) + } + + private func cleanDumpFile() { + try? FileManager.default.removeItem(atPath: dumpFilePath) + } + + /// Main execution flow. + func run() { + do { + cleanDumpFile() + let optArgs = V8DifferentialConfig.commonArgs + V8DifferentialConfig.differentialArgs + try runV8(args: optArgs) + let optDumps = try readDumpFile() + + cleanDumpFile() + let refArgs = V8DifferentialConfig.commonArgs + V8DifferentialConfig.referenceArgs + try runV8(args: refArgs) + let unOptDumps = try readDumpFile() + + let result = DiffOracle.relate(optDumps, with: unOptDumps) + print("Differential check result: \(result)") + + if !result { + exit(1) + } + + } catch { + print("Error during relate: \(error)") + exit(1) + } + } +} + +let args = Arguments.parse(from: CommandLine.arguments) + +guard let jsShellPath = args["--d8"], + let pocPath = args["--poc"] +else { + print("Usage: --d8 --poc [--dump ]") + exit(1) +} + +// Parse optional dump path, default to /tmp/output_dump.txt +let dumpPath = args["--dump"] ?? "/tmp/output_dump.txt" + +let relater = Relater(d8Path: jsShellPath, pocPath: pocPath, dumpFilePath: dumpPath) +relater.run() 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 b8f017ad9..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,19 +28,26 @@ 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() - let lifter = JavaScriptLifter(ecmaVersion: .es6) + let lifter = JavaScriptLifter(ecmaVersion: .es6, environment: JavaScriptEnvironment()) for testcasePath in enumerateAllTestcases() { let testName = URL(fileURLWithPath: testcasePath).lastPathComponent @@ -47,7 +55,7 @@ class CompilerTests: XCTestCase { // Execute the original code and record the output. let result1 = try nodejs.executeScript(at: URL(fileURLWithPath: testcasePath)) guard result1.isSuccess else { - XCTFail("Tescase \(testName) failed to execute. Output:\n\(result1.output)") + XCTFail("TestCase \(testName) failed to execute. Output:\n\(result1.output)") continue } @@ -65,13 +73,17 @@ class CompilerTests: XCTestCase { let script = lifter.lift(program) let result2 = try nodejs.executeScript(script) guard result2.isSuccess else { - XCTFail("Tescase \(testName) failed to execute after compiling and lifting. Output:\n\(result2.output)") + 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/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 369b93090..3289a3180 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'; @@ -15,6 +27,77 @@ console.log("Computed object method"); console.log(obj.theAnswerIs()); })(); +console.log("Indexed object method"); +(() => { + const obj = { 67() { return 42; } }; + console.log(obj[67]()); +})(); + +console.log("String literal object method"); +(() => { + const obj = { "?"() { return 42; } }; + 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) { @@ -37,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) { @@ -62,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) { @@ -89,7 +169,6 @@ console.log("Computed static class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ console.log("Computed class property (method)"); (() => { @@ -136,7 +215,6 @@ console.log("Indexed static class property (field)"); console.log(C[42]); })(); -/* console.log("Indexed class property (method)"); (() => { class C { @@ -148,9 +226,7 @@ console.log("Indexed class property (method)"); const c = new C(); console.log(c[42]()); })(); -*/ -/* console.log("Indexed static class property (method)"); (() => { class C { @@ -161,9 +237,7 @@ console.log("Indexed static class property (method)"); } console.log(C[42]()); })(); -*/ -/* console.log("Indexed class property (getter/setter)"); (() => { class C { @@ -185,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 { @@ -208,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)"); (() => { @@ -250,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 { @@ -274,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 { @@ -297,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)"); (() => { @@ -319,27 +386,26 @@ console.log("String-literal static class property (field)"); console.log("String-literal class property (method)"); (() => { class C { - "theAnswerIs"() { + "theAnswerIs?"() { console.log("Heavy calculations"); return 42; } } const c = new C(); - console.log(c.theAnswerIs()); + console.log(c["theAnswerIs?"]()); })(); console.log("String-literal static class property (method)"); (() => { class C { - static "theAnswerIs"() { + static "theAnswerIs?"() { console.log("Heavy calculations"); return 42; } } - console.log(C.theAnswerIs()); + console.log(C["theAnswerIs?"]()); })(); -/* console.log("String-literal class property (getter/setter)"); (() => { class C { @@ -361,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 { @@ -384,4 +448,3 @@ console.log("String-literal static class property (getter/setter)"); C.theAnswerIs = 42; console.log(C.theAnswerIs); })(); -*/ 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); 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)); diff --git a/Tests/FuzzilliTests/CompilerTests/rest_parameter.js b/Tests/FuzzilliTests/CompilerTests/rest_parameter.js new file mode 100644 index 000000000..fddea0c0c --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/rest_parameter.js @@ -0,0 +1,28 @@ +function f(x, ...rest) { + return x * rest.length; +} +console.log(f(7, 2, 3, 4)); + +// A function expression is parsed differently than a function declaration. +console.log((function funcExpression(...rest) { return rest[2]; })(null, null, 75, null)); + +let arrow = (...values) => values.length; +console.log(arrow(1, 1, 1, 1, 1, 1, 1)); +console.log(((x, y, ...rest) => rest.length)(0, 0, 1, 2, 3, 2, 1)); + +class C { + constructor(...rest) { + this.args = rest; + } + + method(...args) { + return this.args.length * args.length; + } + + static staticMethod(...rest) { + return rest.length; + } +} + +console.log(new C(1, 1, 1, 1, 1, 1).method(2, 2, 2)); +console.log(C.staticMethod(1, 1)); diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index 1ffdbc914..97aec8fa2 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() { + func testReachabilityCalculationForJS() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, isBundle: false, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .javascript)) @@ -26,38 +28,50 @@ class ContextGraphTests: XCTestCase { XCTAssertEqual(reachableContexts, reachableContexts2) - XCTAssertEqual(reachableContexts, - Set([.javascript, - .method, - .classMethod, - .switchCase, - .classDefinition, - .switchBlock, - .asyncFunction, - .wasmFunction, - .wasm, - .loop, - .generatorFunction, - .objectLiteral, - .subroutine, - .wasmTypeGroup])) + var expectedReachedContexts = Set(Context.allCases) + expectedReachedContexts.remove(.empty) + // Only reachable in the "bundle" configuration. + expectedReachedContexts.remove(.bundle) + XCTAssertEqual(reachableContexts, expectedReachedContexts) + } + + func testReachabilityCalculationForBundles() { + let config = Configuration(generateBundle: true) + let fuzzer = makeMockFuzzer(config: config) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, isBundle: true, withLogger: Logger(withLabel: "Test")) + + let reachableContexts = Set(contextGraph.getReachableContexts(from: .bundle)) + + let reachableContexts2 = Set(contextGraph.getReachableContexts(from: .bundle)) + + XCTAssertEqual(reachableContexts, reachableContexts2) + + var expectedReachedContexts = Set(Context.allCases) + expectedReachedContexts.remove(.empty) + XCTAssertEqual(reachableContexts, expectedReachedContexts) } func testSubsetReachabilityCalculation() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, isBundle: false, 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 new file mode 100644 index 000000000..fe8149e8c --- /dev/null +++ b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift @@ -0,0 +1,58 @@ +// 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/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift new file mode 100644 index 000000000..229588f72 --- /dev/null +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -0,0 +1,482 @@ +// 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 + +final class DiffOracleTests: XCTestCase { + + func testSimpleIdentity() { + let dump = """ + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 + + """ + // Should match itself + XCTAssertTrue(DiffOracle.relate(dump, with: dump)) + } + + func testIncrementalParsingLogic() { + // 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: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 + + """ + + XCTAssertTrue(DiffOracle.relate(optFull, with: unopt)) + } + + func testOptimizedOutAccumulator() { + let unopt = """ + ---I + b:10 + f:1 + x:SecretValue + n:0 + m:0 + + """ + + let opt = """ + ---I + b:10 + f:1 + x: + n:0 + m:0 + + """ + + // in Opt should match distinct value in Unopt + XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) + } + + func testOptimizedOutArgument() { + let unopt = """ + ---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 + + """ + + 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 + + """ + + let opt = """ + ---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 + + """ + + let opt = """ + ---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 + + """ + + let opt = """ + ---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:20 + + ---I + b:30 + + ---I + b:40 + + """ + + let opt = """ + ---I + b:10 + f:1 + n:0 + m:0 + + ---I + b:40 + + """ + + XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) + } + + func testOrderMatters() { + // 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:40 + + """ + + let opt = """ + ---I + b:40 + f:1 + n:0 + m:0 + + ---I + b:10 + + """ + + XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) + } + + func testBytecodeOffsetMismatch() { + let unopt = """ + ---I + b:10 + f:1 + n:0 + m:0 + + """ + + let opt = """ + ---I + b:99 + f:1 + n:0 + m:0 + + """ + + XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) + } + + func testArrayResizeUpdateValues() { + // Tests the logic in `updateValues` where it handles missing or excess values + // when n counts change between frames. + + let unopt = """ + ---I + b:10 + f:1 + n:1 + m:0 + a0:A + + ---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:20 + n:2 + a0:A + a1:B + + """ + + XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) + } + + func testRegisterPersistence() { + // Scenario: + // 1. We set r0=A, r1=B (m:2) in the first frame. + // 2. In the second frame we only use r0 (m:1). r1 is NOT in the frame, but should exist in backing store. + // 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 + + """ + + let expectedLastFrame = """ + ---I + b:30 + f:1 + n:0 + m:2 + r0:A_Prime + r1:B + + """ + XCTAssertTrue(DiffOracle.relate(expectedLastFrame, with: trace)) + } + + func testMissingValueInjection() { + // Scenario: + // Frame 1: m=1, r0=A + // 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: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: + + """ + + XCTAssertTrue(DiffOracle.relate(explicitMissing, with: trace)) + } + + func testFarJumpInRegisterIndex() { + // Scenario: A frame references a high register index directly without defining intermediate ones. + // Buffer should auto-grow and fill with . + + let trace = """ + ---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 + + """ + + XCTAssertTrue(DiffOracle.relate(expected, with: trace)) + } + + func testEmptyStringValueParsing() { + let unopt = """ + ---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") + } +} diff --git a/Tests/FuzzilliTests/EngineTests.swift b/Tests/FuzzilliTests/EngineTests.swift index 420698c5c..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 @@ -48,4 +49,62 @@ class EngineTests: XCTestCase { XCTAssertEqual(mockPostProcessor.callCount, 3) XCTAssert(fuzzer.isStopped) } + + // Test that certain usages of "arguments" are rejected by the Dumpling + // post processor. + func testDumplingPostProcessor() { + let fuzzer = makeMockFuzzer() + let processor = DumplingFuzzingPostProcessor() + + let rejectedCases: [(ProgramBuilder) -> Void] = [ + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + b.getProperty("arguments", of: f) + }, + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + let i = b.loadInt(0) + b.setProperty("arguments", of: f, to: i) + }, + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + let i = b.loadInt(0) + b.updateProperty("arguments", of: f, with: i, using: BinaryOperator.Add) + }, + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + b.deleteProperty("arguments", of: f) + }, + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + let a = b.loadString("arguments") + b.getComputedProperty(a, of: f) + }, + ] + + for (i, rejectedCase) in rejectedCases.enumerated() { + let b = fuzzer.makeBuilder() + rejectedCase(b) + let program = b.finalize() + XCTAssertThrowsError(try processor.process(program, for: fuzzer), "test case \(i)") + } + + for acceptedCase: (ProgramBuilder) -> Void in [ + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + b.getProperty("not_arguments", of: f) + }, + { b in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } + let a = b.loadString("not_arguments") + b.getComputedProperty(a, of: f) + }, + ] { + + let b = fuzzer.makeBuilder() + acceptedCase(b) + let program = b.finalize() + _ = try! processor.process(program, for: fuzzer) + } + } } diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index d8dbcf271..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", "--experimental-wasm-rab-integration", "--wasm-test-streaming"]) + 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) @@ -73,84 +76,31 @@ class EnvironmentTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "") } - /// Test that all interesting properties on the globalThis object are registered as builtins. - func testJSEnvironmentRegisteredBuiltins() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .user, withArguments: []) - let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) - let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) - let b = fuzzer.makeBuilder() - - let globalThis = b.createNamedVariable(forBuiltin: "globalThis") - let object = b.createNamedVariable(forBuiltin: "Object") - let names = b.callMethod("getOwnPropertyNames", on: object, withArgs: [globalThis]) - let namesString = b.callMethod("join", on: names, withArgs: [b.loadString(",")]) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [namesString]) - - let prog = b.finalize() - let jsProg = fuzzer.lifter.lift(prog, withOptions: []) - let jsEnvironment = b.fuzzer.environment - let result = testExecuteScript(program: jsProg, runner: runner) - XCTAssert(result.isSuccess, "\(result.error)\n\(result.output)") - var output = result.output - XCTAssertEqual(output.removeLast(), "\n") - - // Global builtins available in d8 that should not be fuzzed. - let skipped = [ - "fuzzilli", "testRunner", "quit", "load", "read", "readline", "readbuffer", - "writeFile", "write", "print", "printErr", "version", "os", "d8", "arguments", "Realm" - ] - // Global builtins that we probably should register but haven't done so, yet. - let TODO = [ - "globalThis", - "Iterator", - "setTimeout", - "console", - "escape", - "unescape", - "encodeURIComponent", - "encodeURI", - "decodeURIComponent", - "decodeURI", - // https://github.com/tc39/proposal-ecmascript-sharedmem/tree/main - "Atomics", - // https://github.com/tc39/proposal-explicit-resource-management - "DisposableStack", - "AsyncDisposableStack", - // https://github.com/tc39/proposal-float16array - "Float16Array", - // Web APIs - "performance", - "Worker", - ] - let ignore = Set(skipped + TODO) - - for builtin in output.split(separator: ",") where !ignore.contains(String(builtin)) { - XCTAssert(jsEnvironment.builtins.contains(String(builtin)), - "Unregistered builtin \(builtin)") - } - } - 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)]) @@ -160,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 56ab52d11..bfb9afd4a 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,13 +147,13 @@ 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")) 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) } @@ -140,20 +162,28 @@ 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(v, to: params[1]) + b.reassign(variable: v, value: params[1]) XCTAssertEqual(b.type(of: v), .float) } 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,12 +257,12 @@ 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) - 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 +271,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 +282,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 +296,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) } @@ -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)) @@ -530,11 +662,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"])) } @@ -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(v, to: 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(v, to: 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,24 +718,26 @@ 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(v0, to: b.loadString("foo")) - b.reassign(v1, to: b.loadString("foo")) - }, elseBody: { - b.reassign(v1, to: 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() 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) @@ -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(v, to: b.loadString("foo")) - XCTAssertEqual(b.type(of: v), .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: 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) } @@ -641,7 +794,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) } } @@ -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(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: 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,20 +1177,20 @@ 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 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 +1202,11 @@ 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) @@ -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(v2, to: b.loadString("foo")) - }, while: { b.reassign(v1, to: 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,15 +1243,19 @@ 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(v1, to: b.loadString("foo")) - }, { - b.reassign(v2, to: b.loadString("bar")) - return b.loadBool(false) - }, { - b.reassign(v3, to: b.loadString("baz")) - }) { - b.reassign(v4, to: b.loadString("bla")) + 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")) } XCTAssertEqual(b.type(of: v1), .jsString) @@ -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,42 +1319,52 @@ 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") - b.reassign(v0, to: stringVar) + b.reassign(variable: v0, value: stringVar) 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) - b.reassign(v0, to: boolVal) + b.reassign(variable: v0, value: boolVal) 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) - b.reassign(v0, to: floatVar) + b.reassign(variable: v0, value: floatVar) XCTAssertEqual(b.type(of: v0), .float) } } 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) } @@ -1150,7 +1379,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 +1400,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) } } @@ -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) @@ -1534,7 +1810,7 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - let wasmSignature = [] => [.wasmExternRef] + let wasmSignature = [] => [.wasmExternRef()] let typeDesc = b.type(of: typeGroup[0]).wasmTypeDefinition!.description! @@ -1551,11 +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.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.WasmBuildLegacyCatch(tag: jsTag) { label, exception, args in - function.wasmReturn() - } - } + function.wasmBuildLegacyTryVoid( + body: { _ in }, + catchClauses: [(tag: jsTag, body: { _, _, _ in })]) function.wasmUnreachable() return [] } @@ -1563,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)] } @@ -1574,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 + 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) @@ -1612,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) @@ -1646,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") @@ -1662,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") @@ -1670,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") @@ -1688,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. @@ -1703,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)) } @@ -1721,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) @@ -1762,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"))) @@ -1780,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) - // WebAssembly.Tag.prototype doesn't have any properties or methods. - XCTAssertEqual(b.type(of: tagPrototype), .object(ofGroup: "WasmTag.prototype")) + 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: [:] ) @@ -1848,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" @@ -1857,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() @@ -1869,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 @@ -1890,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") @@ -1904,4 +2241,47 @@ class JSTyperTests: XCTestCase { XCTAssert(b.type(of: result).Is(requestedCtor)) } } + + func testBufferUnionType() { + // Explicitly verify the properties of the ArrayBuffer | SharedArrayBuffer union type. + let unionType = ILType.jsArrayBuffer | .jsSharedArrayBuffer + + 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(.jsSharedArrayBuffer)) + + // Common properties should be preserved + XCTAssert(unionType.properties.contains("byteLength")) + 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 + + 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/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 7758461d1..03b73e48d 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) } @@ -334,17 +334,17 @@ 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) 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) } @@ -542,6 +544,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) } @@ -549,33 +557,150 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = "foobar" + 42; - const v7 = Symbol.toPrimitive; - const v17 = { - 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; - }, - ...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) + } + + func testObjectLiteralLiftingWeirdNames() { + 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 + } + } + } + + let program = b.finalize() + 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"() { + }, + }; + + """ + 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) } @@ -596,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) } @@ -633,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) } @@ -655,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) @@ -682,6 +807,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 @@ -708,6 +838,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) @@ -737,84 +872,263 @@ 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) 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) { - } - 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(a26) { - } - #ifoo; - #ibar = "baz"; - #im() { - const v28 = this.#ifoo; - this.#ibar = v28; - return v28; + 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; + } } - #in(a30) { - this.#im(); - this.#ibar += a30; + new C7(42); + C7 = Uint8Array; + + """ + + XCTAssertEqual(actual, expected) + } + + func testClassDefinitionLiftingWeirdNames() { + 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 + } } - static #sfoo; - static #sbar = "baz"; - static #sm() { - const v33 = this.#sfoo; - this.#sbar = v33; - return v33; + } + + let program = b.finalize() + 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"() { + } } - static #sn(a35) { - this.#sm(); - this.#sbar += a35; + + """ + + 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 + } } } - new C7(42); - C7 = Uint8Array; - """ + 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) } @@ -835,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) } @@ -859,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) } @@ -882,12 +1196,12 @@ 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()]) 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]) @@ -896,30 +1210,54 @@ 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) } - func testBinaryOperationLifting() { + func testHoleyArrayLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let Math = b.createNamedVariable(forBuiltin: "Math") - let v = b.callMethod("random", on: Math) - let two_v = b.binary(v, v, with: .Add) - let three_v = b.binary(two_v, v, with: .Add) - let twelve_v = b.binary(b.loadInt(4), three_v, with: .Mul) - let six_v = b.binary(twelve_v, b.loadInt(2), with: .Div) + let v0 = b.loadInt(42) + let v1 = b.loadUndefined() + // Should lift to: [42,,,42] + b.createArray(with: [v0, v1, v1, v0]) + + // Should lift to: [,,] + b.createArray(with: [v1, v1]) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + [42,,,42]; + [,,]; + + """ + + XCTAssertEqual(actual, expected) + } + + func testBinaryOperationLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let Math = b.createNamedVariable(forBuiltin: "Math") + let v = b.callMethod("random", on: Math) + let two_v = b.binary(v, v, with: .Add) + let three_v = b.binary(two_v, v, with: .Add) + let twelve_v = b.binary(b.loadInt(4), three_v, with: .Mul) + let six_v = b.binary(twelve_v, b.loadInt(2), with: .Div) let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [six_v]) @@ -928,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) } @@ -941,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) } @@ -962,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]) @@ -992,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) @@ -1027,24 +1365,21 @@ 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() let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - return a1; - } - f0(13.37); - const v4 = () => { - return "foobar"; - }; - f0 = v4; - f0(); + function f0(a1) { + return a1; + } + f0(13.37); + f0 = () => "foobar"; + f0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1055,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)]) @@ -1069,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) } @@ -1102,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) } @@ -1131,11 +1469,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - foo(); - function foo() { - } + foo(); + function foo() { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -1150,23 +1488,23 @@ 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() 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) } @@ -1187,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) } @@ -1213,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) @@ -1223,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) } @@ -1236,9 +1584,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) @@ -1247,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) } @@ -1266,25 +1614,25 @@ 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) 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) } @@ -1297,38 +1645,41 @@ 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]) @@ -1336,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) } @@ -1375,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) } @@ -1411,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) } @@ -1426,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) @@ -1436,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) @@ -1444,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) } @@ -1470,16 +1822,19 @@ 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)) + 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)) @@ -1491,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) } @@ -1537,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) } @@ -1574,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) } @@ -1608,32 +1963,33 @@ 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) - b.reassign(v3, to: b.loadString("foo")) - b.reassign(v4, to: b.loadString("bar")) - b.reassign(v3, to: b.loadString("baz")) + 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")) let program = b.finalize() 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) } @@ -1649,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) } @@ -1676,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) } @@ -1698,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) } @@ -1723,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) } @@ -1743,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) } @@ -1779,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) } @@ -1807,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) } @@ -1833,9 +2189,138 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - ("Hello World")[Symbol.iterator]().next(); + ("Hello World")[Symbol.iterator]().next(); + + """ + + XCTAssertEqual(actual, expected) + } + + func testMethodCallLiftingWeirdNames() { + 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.callMethod(name, on: obj) + } + + let program = b.finalize() + 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"](); + + """ + + XCTAssertEqual(actual, expected) + } + + func testMethodCallWithSpreadLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + 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]) + } + + let program = b.finalize() + 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); + + """ + + XCTAssertEqual(actual, expected) + } + + func testMethodBindLiftingWeirdNames() { + 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"] { + let bound = b.bindMethod(name, on: obj) + b.callFunction(bound, withArgs: [obj]) + } + + let program = b.finalize() + 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); + + """ + + XCTAssertEqual(actual, expected) + } + + func testSuperMethodCallLiftingWeirdNames() { + 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.callSuperMethod(name) + } + } + } + + let program = b.finalize() + 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"](); + } + } - """ + """ XCTAssertEqual(actual, expected) } @@ -1854,9 +2339,99 @@ 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) + } + + 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) } @@ -1874,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) } @@ -1891,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 } @@ -1917,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) } @@ -1947,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 } @@ -1962,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)]) @@ -1976,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) @@ -2019,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) } @@ -2038,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) } @@ -2073,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) } @@ -2105,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) } @@ -2136,7 +2711,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() @@ -2147,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) } @@ -2167,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)]) @@ -2181,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) } @@ -2200,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)]) @@ -2214,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) } @@ -2233,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)]) @@ -2250,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) } @@ -2272,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) @@ -2281,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) { @@ -2296,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) } @@ -2329,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) } @@ -2352,10 +2934,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - while (shouldContinue()) { - } + while (shouldContinue()) { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2367,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) } @@ -2375,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) } @@ -2391,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")) } @@ -2415,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) } @@ -2445,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) } @@ -2465,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]) @@ -2474,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) } @@ -2492,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) } @@ -2522,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) } @@ -2548,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) } @@ -2574,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]) } @@ -2585,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) } @@ -2600,7 +3218,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop() { + b.buildForLoop { b.loopBreak() } @@ -2608,11 +3226,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (;;) { - break; - } + for (;;) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2621,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) } @@ -2631,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) } @@ -2643,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(vs[0], to: 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) } @@ -2653,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) } @@ -2673,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(shouldContinue, to: 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() } @@ -2688,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) } @@ -2709,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($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]) } @@ -2717,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) } @@ -2730,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() } @@ -2738,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) } @@ -2757,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(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 } } @@ -2765,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) } @@ -2785,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]) @@ -2794,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) } @@ -2815,9 +3473,15 @@ 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(s, to: arg, with: .Add) + b.reassign(variable: s, value: arg, with: .Add) } b.doReturn(s) } @@ -2826,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) } @@ -2845,7 +3509,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]) @@ -2854,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) } @@ -2869,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]) @@ -2885,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) } @@ -2906,10 +3572,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) + let v4 = b.createObject(with: ["a": v1]) + b.reassign(variable: v2, value: v4) } } @@ -2919,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) } @@ -2995,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) } @@ -3030,24 +3696,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) } } @@ -3055,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; + let v0 = this; + v0 = 42; + function F2() { + if (!new.target) { throw 'must be called with new'; } + let v3 = this; + v3 = 42; } - static get baz() { - let v8 = this; - v8 = 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) } @@ -3106,7 +3772,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) @@ -3116,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) } @@ -3140,25 +3806,27 @@ 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() 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() @@ -3166,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) } } @@ -3183,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() @@ -3223,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) } } @@ -3239,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)) } @@ -3285,11 +3964,12 @@ 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 - f.wasmCallIndirect(signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) + f.wasmCallIndirect( + signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) return [] } } @@ -3301,7 +3981,7 @@ class LifterTests: XCTestCase { let _ = lifter.lift(prog) // Now we build the mutated Program. - b.beginAdoption(from: prog) + b.beginAdoption() for i in 0.. 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) + } + + func testArrowFunctionInliningWithSideEffects() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let f = b.createNamedVariable(forBuiltin: "sideEffect") + b.callFunction(f) + + let arrow = b.buildArrowFunction(with: .parameters(n: 0)) { _ in + b.doReturn(b.loadInt(42)) + } + + b.callFunction(arrow) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + // 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(); + + """ + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionRecursiveLifting() { + let fuzzer = makeMockFuzzer() + // Manually construct a recursive arrow function, as the helper does not support it. + let b2 = fuzzer.makeBuilder() + let i = b2.loadInt(10) + let params = Parameters(count: 1) + let instr = b2.emit(BeginArrowFunction(parameters: params)) + let fRec = instr.output + let arg0 = instr.innerOutput(0) + + let cond = b2.compare(arg0, with: b2.loadInt(0), using: .equal) + b2.buildIf(cond) { + b2.doReturn(b2.loadInt(0)) + } + let sub = b2.binary(arg0, b2.loadInt(1), with: .Sub) + let recCall = b2.callFunction(fRec, withArgs: [sub]) // Recursion! + b2.doReturn(recCall) + b2.emit(EndArrowFunction()) + + b2.callFunction(fRec, withArgs: [i]) + + let program2 = b2.finalize() + let actual = fuzzer.lifter.lift(program2) + + // 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); + + """ + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionAsArgument() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let f = b.createNamedVariable(forBuiltin: "f") + let arrow = b.buildArrowFunction(with: .parameters(n: 1)) { args in + b.doReturn(args[0]) + } + b.callFunction(f, withArgs: [arrow]) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + f((a2) => a2); + + """ + XCTAssertEqual(actual, expected) + } + + func testNestedArrowFunctions() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + 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(arrowInner) + } + b.callFunction(arrowOuter, withArgs: [b.loadInt(1)]) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const t0 = (a1) => (a3) => a1 + a3; + t0(1); + + """ + XCTAssertEqual(actual, expected) + } + + func testAsyncArrowFunctionInlining() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let arrow = b.buildAsyncArrowFunction(with: .parameters(n: 0)) { _ in + b.doReturn(b.loadInt(42)) + } + b.callFunction(arrow) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const t0 = async () => 42; + t0(); + + """ + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionMultipleUses() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let arrow = b.buildArrowFunction(with: .parameters(n: 0)) { _ in } + let f = b.createNamedVariable(forBuiltin: "f") + b.callFunction(f, withArgs: [arrow, arrow]) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v0 = () => { + }; + f(v0, v0); + + """ + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionPropertyAssignment() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createNamedVariable(forBuiltin: "obj") + let arrow = b.buildArrowFunction(with: .parameters(n: 0)) { _ in + b.doReturn(b.loadInt(42)) + } + b.setProperty("x", of: obj, to: arrow) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + obj.x = () => 42; + + """ + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionObjectLiteral() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let o = b.buildObjectLiteral { _ in } + let f = b.buildArrowFunction(with: .parameters(n: 0)) { _ in + b.doReturn(b.buildObjectLiteral { _ in }) + } + b.setProperty("x", of: o, to: f) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v0 = {}; + v0.x = () => ({}); + + """ + XCTAssertEqual(actual, expected) + } + + func testNestedArrowFunctionIndentation() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + 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)) + b.doReturn(b.binary(v, v, with: .Add)) + } + b.setProperty("x", of: o, to: f) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + if (true) { + const v1 = {}; + v1.x = () => { + const a = 1; + return a + a; + }; + } + + """ + XCTAssertEqual(actual, expected) + } + + func testConciseArrowFunctionStartingWithObjectLiteral() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let f = b.buildArrowFunction(with: .parameters(n: 0)) { _ in + let o = b.buildObjectLiteral { _ in } + let i = b.loadInt(1) + b.doReturn(b.binary(o, i, with: .Add)) + } + b.callFunction(f) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const t0 = () => ({} + 1); + t0(); + + """ + XCTAssertEqual(actual, expected) + } + + func testStringEscape() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + let v1 = b.loadString("Hello \"World\"") + let p = b.createNamedVariable(forBuiltin: "print") + b.callFunction(p, withArgs: [v1]) + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + print("Hello \\"World\\""); + + """ - """ 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) + } + + 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) + } + + 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) + } + + func testBundleScripts() { + let config = Configuration(generateBundle: true) + let fuzzer = makeMockFuzzer(config: config) + let b = fuzzer.makeBuilder() + + b.emit(BeginBundleScript()) + let Object = b.createNamedVariable(forBuiltin: "Object") + b.construct(Object) + b.emit(EndBundleScript()) + + b.emit(BeginBundleScript()) + let Array = b.createNamedVariable(forBuiltin: "Array") + b.construct(Array) + b.emit(EndBundleScript()) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + // JS_BUNDLE_SCRIPT + new Object(); + // JS_BUNDLE_SCRIPT + new Array(); + + """ + + XCTAssertEqual(actual, expected) + } + } diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 4ffb8c5d9..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: ["--experimental-wasm-exnref", "--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: ["--experimental-wasm-exnref", "--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)! + } } } @@ -133,18 +143,19 @@ class LiveTests: XCTestCase { b.buildTryCatchFinally { // TODO(manoskouk): Once we support wasm-gc types in signatures, we'll need // something more sophisticated. + // TODO(pawkra): support shared refs. let args = wasmSignature.parameterTypes.map { switch $0 { - case .wasmi64: - return b.loadBigInt(123) - case .wasmFuncRef: - return jsFunction - case .wasmNullExternRef, .wasmNullFuncRef, .wasmNullRef: - return b.loadNull() - case .wasmExternRef, .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) @@ -157,14 +168,18 @@ class LiveTests: XCTestCase { } } - // We expect a maximum of 25% of Wasm execution attempts to fail. - checkFailureRate(testResults: results, maxFailureRate: 0.25) + // TODO(mliedtke): Figure out how to handle ref.cast and lower it. + // We expect a maximum of 35% of Wasm execution attempts to fail. + checkFailureRate(testResults: results, maxFailureRate: 0.35) } // 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. @@ -176,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 {} } @@ -200,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 } @@ -208,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 @@ -222,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 8d9a29664..d6c5eb7cf 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 { @@ -355,7 +356,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 +409,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 +467,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 +511,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -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(r, to: a2) - }, elseBody: { - b.reassign(r, to: 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) @@ -651,6 +658,128 @@ class MinimizerTests: XCTestCase { XCTAssertEqual(expectedProgram, actualProgram) } + func testInliningWithSemiConditionalReturn() { + /* + Show that inlining with conditional returns migth not be + semantically equivalent. + + Input: + function f1() { + if (true) { + return 1; + } + return 2; + } + let v1 = f1(); + {result: v1} + + Is inlined to: + var v1 = undefined; + if (true) { + v1 = 1; + } + v1 = 2; + + {result: 2} + */ + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + var a1 = b.loadBool(true) + var a2 = b.loadInt(1) + 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.doReturn(a3) + } + + var r = b.callFunction(f, withArgs: []) + var o = b.createObject(with: [:]) + evaluator.nextInstructionIsImportant(in: b) + b.setProperty("result", of: o, to: r) + + let originalProgram = b.finalize() + + // Need to keep various things alive, see also the comment in testBasicInlining + evaluator.operationIsImportant(LoadInteger.self) + evaluator.operationIsImportant(LoadBoolean.self) + evaluator.operationIsImportant(BeginIf.self) + evaluator.operationIsImportant(Reassign.self) + evaluator.keepReturnsInFunctions = true + + // Build expected output program. + a1 = b.loadBool(true) + a2 = b.loadInt(1) + a3 = b.loadInt(2) + r = b.loadUndefined() + 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) + + let expectedProgram = b.finalize() + + // Perform minimization and check that the two programs are equal. + let actualProgram = minimize(originalProgram, with: fuzzer) + XCTAssertEqual(expectedProgram, actualProgram) + } + + // Ensure we don't crash when a candidate function is also used as a + // disposable variable. + func testInliningWithDisposableVariable() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + let a1 = b.loadBool(true) + + // The function to be inlined. + let f = b.buildPlainFunction(with: .parameters(n: 0)) { args in + b.doReturn(a1) + } + + // The call and result. + evaluator.nextInstructionIsImportant(in: b) + let r = b.callFunction(f, withArgs: []) + let o = b.createObject(with: [:]) + evaluator.nextInstructionIsImportant(in: b) + b.setProperty("result", of: o, to: r) + + // Another function with a disposable variable refering + // to the first function. + evaluator.nextInstructionIsImportant(in: b) + b.buildPlainFunction(with: .parameters(n: 0)) { args in + evaluator.nextInstructionIsImportant(in: b) + b.loadDisposableVariable(f) + b.doReturn(a1) + } + + let originalProgram = b.finalize() + + // Need to keep various things alive, see also the comment in testBasicInlining + evaluator.operationIsImportant(LoadBoolean.self) + evaluator.operationIsImportant(Reassign.self) + evaluator.keepReturnsInFunctions = true + + // Perform minimization and check that the two programs are equal. + // We expect the no changes as the inlining candidate was used as + // a disposable variable. + let actualProgram = minimize(originalProgram, with: fuzzer) + XCTAssertEqual(originalProgram, actualProgram) + } + func testMultiInlining() { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -717,26 +846,29 @@ 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.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 + 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.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.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.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.setProperty("n3", of: o, to: n3) // This will store n3, 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 evaluator.operationIsImportant(Reassign.self) @@ -751,26 +883,29 @@ 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.setProperty("n1", of: o, to: n5) - b.setProperty("n1", of: o, to: n5) - b.reassign(n1, to: n2) - b.setProperty("n1", of: o, to: n2) - }, elseBody: { - let n6 = b.loadInt(47) - b.reassign(n1, to: 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(n1, to: n2) + b.reassign(variable: n1, value: n2) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n3", of: o, to: n3) @@ -881,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() @@ -919,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]) } @@ -964,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]) } @@ -980,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) @@ -1004,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]) @@ -1047,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) @@ -1224,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() @@ -1316,6 +1492,39 @@ class MinimizerTests: XCTestCase { XCTAssertEqual(expectedProgram, actualProgram) } + func testDestructuringSimplificationWithRest() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + var o = b.createNamedVariable(forBuiltin: "TheArray") + let vars = b.destruct(o, selecting: [0, 2], lastIsRest: true) + + var print = b.createNamedVariable(forBuiltin: "print") + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(print, withArgs: [vars[0], vars[1]]) + + let originalProgram = b.finalize() + + // Build expected output program. + o = b.createNamedVariable(forBuiltin: "TheArray") + let e0 = b.getElement(0, of: o) + let restVars = b.destruct(o, selecting: [2], lastIsRest: true) + + print = b.createNamedVariable(forBuiltin: "print") + b.callFunction(print, withArgs: [e0, restVars[0]]) + + let expectedProgram = b.finalize() + + // See testDestructuringSimplification2 for why these are marked important. + evaluator.operationIsImportant(DestructArray.self) + evaluator.operationIsImportant(GetElement.self) + + let actualProgram = minimize(originalProgram, with: fuzzer) + XCTAssertEqual(actualProgram, expectedProgram) + } + func testVariableDeduplication() { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -1363,6 +1572,44 @@ class MinimizerTests: XCTestCase { XCTAssertEqual(expectedProgram, actualProgram) } + func testBundleMinimizing() { + let config = Configuration(generateBundle: true) + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(config: config, evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + + // Script with an important instruction. + b.emit(BeginBundleScript()) + var foo = b.createNamedVariable(forBuiltin: "foo") + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(foo) + b.emit(EndBundleScript()) + + // Script with an unimportant instruction. + b.emit(BeginBundleScript()) + foo = b.createNamedVariable(forBuiltin: "foo") + b.callFunction(foo) + b.emit(EndBundleScript()) + + let originalProgram = b.finalize() + + // Build expected output program. + + // Expect only the script with the important instruction to be preserved. + b.emit(BeginBundleScript()) + foo = b.createNamedVariable(forBuiltin: "foo") + b.callFunction(foo) + b.emit(EndBundleScript()) + + let expectedProgram = b.finalize() + + // Perform minimization and check that the two programs are equal. + let actualProgram = minimize(originalProgram, with: fuzzer) + XCTAssertEqual(expectedProgram, actualProgram) + } + func testGuardedOperationSimplification() { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -1378,7 +1625,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() @@ -1387,8 +1637,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 }) @@ -1401,7 +1655,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() @@ -1422,9 +1679,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. @@ -1432,25 +1690,26 @@ class MinimizerTests: XCTestCase { try runWasmMinimization { evaluator, b in return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + // Mark the try instruction as important (the next instruction is the signature). + evaluator.instructionNIsImportant(in: b, n: 2) + function.wasmBuildLegacyTryVoid { label in let val = function.consti64(42) evaluator.nextInstructionIsImportant(in: b) function.wasmReturn(val) } catchAllBody: { label in function.wasmReturn(function.consti64(-1)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } } minified: { b in return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid { label in function.wasmReturn(function.consti64(42)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } } @@ -1464,19 +1723,25 @@ class MinimizerTests: XCTestCase { let irrelevantTag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - evaluator.nextInstructionIsImportant(in: b) - function.WasmBuildThrow(tag: tag, inputs: []) - evaluator.nextInstructionIsImportant(in: b) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - let val = function.consti64(42) + function.wasmBuildLegacyTryVoid( + body: { label in evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - } - function.WasmBuildLegacyCatch(tag: irrelevantTag) { label, exception, args in - } - } - return [function.consti32(-1)] + 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 }), + ]) + return [function.consti64(-1)] } } @@ -1484,13 +1749,19 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in let tag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.WasmBuildThrow(tag: tag, inputs: []) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmReturn(function.consti64(42)) - } - } - return [function.consti32(-1)] + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: []) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, _ in + function.wasmReturn(function.consti64(42)) + } + ) + ]) + return [function.consti64(-1)] } } } @@ -1502,23 +1773,22 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in let tag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - let val = function.consti64(42) + function.wasmBuildLegacyTryVoid( + body: { label in + let val = function.consti64(42) evaluator.nextInstructionIsImportant(in: b) function.wasmReturn(val) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmUnreachable() - } - } - return [function.consti32(-1)] + }, + catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) + return [function.consti64(-1)] } } } minified: { b in return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmReturn(function.consti64(42)) - return [function.consti32(-1)] + function.wasmReturn(function.consti64(42)) + return [function.consti64(-1)] } } } @@ -1530,12 +1800,9 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in let tag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmReturn(function.consti64(123)) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmUnreachable() - } - } + function.wasmBuildLegacyTryVoid( + body: { _ in function.wasmReturn(function.consti64(123)) }, + catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) evaluator.nextInstructionIsImportant(in: b) return [function.consti64(42)] } @@ -1554,10 +1821,10 @@ class MinimizerTests: XCTestCase { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in - function.wasmBuildIfElse(args[0], hint: .None) { + function.wasmBuildIfElse(args[0], signature: [] => []) { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(43) - } elseBody: { + } elseBody: { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(42) } @@ -1579,9 +1846,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) @@ -1595,8 +1865,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) } @@ -1609,9 +1882,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) @@ -1625,8 +1901,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) } @@ -1639,8 +1918,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) @@ -1654,7 +1936,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)] @@ -1666,8 +1949,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) @@ -1681,7 +1967,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)] @@ -1694,8 +1981,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]] @@ -1708,8 +1998,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 @@ -1725,8 +2018,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) @@ -1739,8 +2035,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) @@ -1755,8 +2054,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 @@ -1769,7 +2072,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)] @@ -1781,8 +2085,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) @@ -1795,7 +2103,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)] @@ -1807,8 +2116,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]] @@ -1819,9 +2132,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)] } @@ -1829,12 +2143,16 @@ class MinimizerTests: XCTestCase { } } - // Don't minimize the block fi the label is used by an important instruction. + // Don't minimize the block if the label is used by an important instruction. 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 @@ -1845,9 +2163,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 } @@ -1860,8 +2182,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]] @@ -1872,9 +2198,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)] } @@ -1937,9 +2264,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))") } @@ -1969,7 +2297,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) @@ -1992,7 +2321,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] } @@ -2002,12 +2332,68 @@ 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 testWasmTypeGroupTypeOnlyUsedInDependency() throws { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + do { + let typeGroup = b.wasmDefineTypeGroup { + // 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]) + return [signature, structType] + } + + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [] => [.wasmAnyRef()]) { function, label, args in + evaluator.nextInstructionIsImportant(in: b) + return [function.wasmStructNewDefault(structType: typeGroup[1])] + } + } + } + let originalProgram = b.finalize() + + // 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]) + return [signature, structType] + } + + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [] => [.wasmAnyRef()]) { function, label, args in + return [function.wasmStructNewDefault(structType: typeGroup[1])] + } + } + } + let expectedProgram = b.finalize() + + // 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))") + } + func testWasmTypeGroupNestedTypesAndTypeGroupDependencies() throws { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -2028,9 +2414,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]), ] } @@ -2052,7 +2442,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 @@ -2067,9 +2461,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))") } @@ -2111,16 +2506,20 @@ class MinimizerTests: XCTestCase { var keepReturnsInFunctions = false /// The program currently being evaluated. - var currentProgram = Program() + var currentProgram = Program(isBundle: false) /// The reference program against which reductions are performed. /// At the start, this is the original program. After a successful reduction, it is replaced by the current program. - var referenceProgram = Program() + var referenceProgram = Program(isBundle: false) func nextInstructionIsImportant(in b: ProgramBuilder) { initialIndicesOfTheImportantInstructions.append(b.indexOfNextInstruction()) } + func instructionNIsImportant(in b: ProgramBuilder, n: Int) { + initialIndicesOfTheImportantInstructions.append(b.indexOfNextInstruction() + n - 1) + } + func operationIsImportant(_ op: Fuzzilli.Operation.Type) { importantOperations.insert(op.name) } @@ -2154,10 +2553,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 + let numImportantInstructionsBefore = importantInstructions.count + var numImportantInstructionsAfter = 0 for instr in referenceProgram.code { if instr.op is BeginAnyFunction { @@ -2197,7 +2600,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 } @@ -2226,7 +2631,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 } @@ -2234,10 +2641,87 @@ 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) + } + + 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))") } } diff --git a/Tests/FuzzilliTests/MutatorTests.swift b/Tests/FuzzilliTests/MutatorTests.swift index 69137207b..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(from: prog) { + 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 2932757cb..6ed19b068 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) } @@ -431,8 +436,6 @@ class ProgramBuilderTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - XCTAssert(b.enableRecursionGuard) - // The recursion guard feature of the ProgramBuilder is meant to prevent trivial recursion // where a newly created function directly calls itself. It's also meant to prevent somewhat // odd code from being generated where operation inside a function's body operate on the function @@ -508,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 @@ -516,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. @@ -530,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 } @@ -538,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() { @@ -562,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"]) @@ -582,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)) } @@ -601,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)) } @@ -620,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() @@ -822,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() // @@ -858,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) @@ -925,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() @@ -1027,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) @@ -1058,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() @@ -1128,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() @@ -1169,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) } @@ -1212,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() @@ -1238,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() @@ -1265,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) } } @@ -1302,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) } } @@ -1456,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") @@ -1483,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) @@ -1520,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() @@ -1675,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() @@ -1865,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() @@ -1965,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() } @@ -1986,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() } @@ -1999,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 // @@ -2009,15 +2070,17 @@ 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) 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]) } @@ -2037,12 +2100,12 @@ 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 + 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() @@ -2058,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 } @@ -2089,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 } } @@ -2105,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 } } @@ -2131,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() @@ -2164,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() @@ -2180,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) @@ -2207,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() @@ -2255,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() // @@ -2340,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(e, to: 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() // @@ -2369,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() @@ -2392,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() { @@ -2412,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") @@ -2433,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") @@ -2461,13 +2537,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() @@ -2495,13 +2571,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() @@ -2539,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)) } @@ -2570,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 @@ -2581,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() @@ -2615,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() @@ -2633,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() @@ -2657,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() @@ -2682,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() @@ -2731,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() { @@ -2780,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) } } @@ -2797,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`. @@ -2830,6 +2931,7 @@ class ProgramBuilderTests: XCTestCase { XCTAssertEqual(typesB.count, 1) } + // TODO(pawkra): check shared subtyping once we support more shared refs. func testWasmGCSubtyping() { let env = JavaScriptEnvironment() let config = Configuration(logLevel: .error) @@ -2837,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] @@ -2865,21 +2970,21 @@ class ProgramBuilderTests: XCTestCase { let arrayI32Type = b.type(of: arrayI32) XCTAssert(arrayI32Type.Is(.wasmRef(.Index(), nullability: true))) XCTAssert(arrayI32Type.Is(.wasmRef(.Index(), nullability: false))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmArray), nullability: true))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmArray), nullability: false))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmEq), nullability: true))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmEq), nullability: false))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmAny), nullability: true))) - XCTAssert(arrayI32Type.Is(.wasmRef(.Abstract(.WasmAny), nullability: false))) - XCTAssertFalse(arrayI32Type.Is(.wasmRef(.Abstract(.WasmStruct), nullability: true))) - XCTAssertFalse(arrayI32Type.Is(.wasmRef(.Abstract(.WasmStruct), nullability: false))) - XCTAssertFalse(arrayI32Type.Is(.wasmRef(.Abstract(.WasmExn), nullability: false))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmArray, nullability: true))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmArray, nullability: false))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmEq, nullability: true))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmEq, nullability: false))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmAny, nullability: true))) + XCTAssert(arrayI32Type.Is(.wasmRef(.WasmAny, nullability: false))) + XCTAssertFalse(arrayI32Type.Is(.wasmRef(.WasmStruct, nullability: true))) + XCTAssertFalse(arrayI32Type.Is(.wasmRef(.WasmStruct, nullability: false))) + XCTAssertFalse(arrayI32Type.Is(.wasmRef(.WasmExn, nullability: false))) let arrayI32B = function.wasmArrayNewFixed(arrayType: arrayDefI32B, elements: []) let arrayI32BType = b.type(of: arrayI32B) XCTAssertFalse(arrayI32BType.Is(arrayI32Type)) XCTAssertFalse(arrayI32Type.Is(arrayI32BType)) - let refArrayType = ILType.wasmRef(.Abstract(.WasmArray), nullability: false) + let refArrayType = ILType.wasmRef(.WasmArray, nullability: false) XCTAssertEqual(arrayI32Type.union(with: arrayI32BType), refArrayType) XCTAssertEqual(arrayI32BType.union(with: arrayI32Type), refArrayType) XCTAssertEqual(arrayI32Type.intersection(with: arrayI32BType), .nothing) @@ -2889,14 +2994,14 @@ class ProgramBuilderTests: XCTestCase { let structType = b.type(of: structVar) XCTAssert(structType.Is(.wasmRef(.Index(), nullability: true))) XCTAssert(structType.Is(.wasmRef(.Index(), nullability: false))) - XCTAssert(structType.Is(.wasmRef(.Abstract(.WasmStruct), nullability: false))) - XCTAssert(structType.Is(.wasmRef(.Abstract(.WasmEq), nullability: false))) - XCTAssert(structType.Is(.wasmRef(.Abstract(.WasmAny), nullability: false))) - XCTAssertFalse(structType.Is(.wasmRef(.Abstract(.WasmArray), nullability: true))) - XCTAssertFalse(structType.Is(.wasmRef(.Abstract(.WasmArray), nullability: false))) - XCTAssertFalse(structType.Is(.wasmRef(.Abstract(.WasmExn), nullability: false))) - - let refEqType = ILType.wasmRef(.Abstract(.WasmEq), nullability: false) + XCTAssert(structType.Is(.wasmRef(.WasmStruct, nullability: false))) + XCTAssert(structType.Is(.wasmRef(.WasmEq, nullability: false))) + XCTAssert(structType.Is(.wasmRef(.WasmAny, nullability: false))) + XCTAssertFalse(structType.Is(.wasmRef(.WasmArray, nullability: true))) + XCTAssertFalse(structType.Is(.wasmRef(.WasmArray, nullability: false))) + XCTAssertFalse(structType.Is(.wasmRef(.WasmExn, nullability: false))) + + let refEqType = ILType.wasmRef(.WasmEq, nullability: false) XCTAssertEqual(structType.union(with: arrayI32Type), refEqType) XCTAssertEqual(arrayI32Type.union(with: structType), refEqType) XCTAssertEqual(structType.intersection(with: arrayI32Type), .nothing) @@ -2905,25 +3010,25 @@ class ProgramBuilderTests: XCTestCase { let i31 = function.wasmRefI31(function.consti32(42)) let i31Type = b.type(of: i31) XCTAssertFalse(i31Type.Is(.wasmRef(.Index(), nullability: true))) - XCTAssert(i31Type.Is(.wasmRef(.Abstract(.WasmEq), nullability: false))) - XCTAssert(i31Type.Is(.wasmRef(.Abstract(.WasmAny), nullability: false))) - XCTAssertFalse(i31Type.Is(.wasmRef(.Abstract(.WasmArray), nullability: false))) - XCTAssertFalse(i31Type.Is(.wasmRef(.Abstract(.WasmStruct), nullability: false))) - XCTAssertFalse(i31Type.Is(.wasmRef(.Abstract(.WasmExn), nullability: false))) + XCTAssert(i31Type.Is(.wasmRef(.WasmEq, nullability: false))) + XCTAssert(i31Type.Is(.wasmRef(.WasmAny, nullability: false))) + XCTAssertFalse(i31Type.Is(.wasmRef(.WasmArray, nullability: false))) + XCTAssertFalse(i31Type.Is(.wasmRef(.WasmStruct, nullability: false))) + XCTAssertFalse(i31Type.Is(.wasmRef(.WasmExn, nullability: false))) XCTAssertEqual(structType.union(with: i31Type), refEqType) XCTAssertEqual(arrayI32Type.union(with: i31Type), refEqType) XCTAssertEqual(i31Type.union(with: refEqType), refEqType) XCTAssertEqual(refArrayType.union(with: i31Type), refEqType) - let refStructType = ILType.wasmRef(.Abstract(.WasmStruct), nullability: false) + let refStructType = ILType.wasmRef(.WasmStruct, nullability: false) XCTAssertEqual(i31Type.union(with: refStructType), refEqType) XCTAssertEqual(i31Type.intersection(with: refEqType), i31Type) XCTAssertEqual(refEqType.intersection(with: i31Type), i31Type) - let refNone = ILType.wasmRef(.Abstract(.WasmNone), nullability: false) + let refNone = ILType.wasmRef(.WasmNone, nullability: false) XCTAssertEqual(i31Type.intersection(with: refArrayType), refNone) XCTAssertEqual(refStructType.intersection(with: i31Type), refNone) - XCTAssertEqual(i31Type.intersection(with: .wasmExnRef), .nothing) + XCTAssertEqual(i31Type.intersection(with: .wasmExnRef()), .nothing) return [] } @@ -2939,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) + ] } } } @@ -2951,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) + ] } } } @@ -2982,34 +3094,52 @@ class ProgramBuilderTests: XCTestCase { // XCTAssertGreaterThan(numGeneratedInstructions, 30) } - func testWasmCallDirectGeneratorSchedulingTest() { + func testWasmMemorySizeSchedulingTest() { let fuzzer = makeMockFuzzer() - let b = fuzzer.makeBuilder() - b.buildPrefix() + let numPrograms = 30 - // Pick the Branch Generator. - let generator = fuzzer.codeGenerators.filter { - $0.name == "WasmStructNewDefaultGenerator" - }[0] + for _ in 0...numPrograms { + let b = fuzzer.makeBuilder() + b.buildPrefix() - // Now build this. - let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) - XCTAssertNotNil(syntheticGenerator) + let generator = fuzzer.codeGenerators.filter { + $0.name == "WasmMemorySizeGenerator" + }[0] + + // Now build this. + let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) + XCTAssertNotNil(syntheticGenerator) + + let N = 30 + // We might generate a lot more than 30 instructions to fulfill the constraints. + let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: N) - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) - XCTAssertGreaterThan(numGeneratedInstructions, 0) + let program = b.finalize() + + XCTAssertTrue( + program.code.contains(where: { instr in + if case .wasmMemorySize = instr.op.opcode { + return true + } else { + return false + } + })) + XCTAssertGreaterThan(numGeneratedInstructions, 0) + } } - func testWasmMemorySizeSchedulingTest() { + func testTypedArrayFromBufferGenerator() { let fuzzer = makeMockFuzzer() - let numPrograms = 100 + let numPrograms = 30 for _ in 0...numPrograms { let b = fuzzer.makeBuilder() - b.buildPrefix() + // Instead of loading a prefix, emit a single integer, so that we have a "prefix" but + // the prefix does not fulfill the requirements for the generator, yet. + b.loadInt(123) let generator = fuzzer.codeGenerators.filter { - $0.name == "WasmMemorySizeGenerator" + $0.name == "TypedArrayFromBufferGenerator" }[0] // Now build this. @@ -3019,20 +3149,114 @@ class ProgramBuilderTests: XCTestCase { let N = 30 // We might generate a lot more than 30 instructions to fulfill the constraints. 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 } + }) + // All generator `produces` guarantees are fulfilled. + XCTAssert(generator.produces.allSatisfy { b.randomVariable(ofType: $0.type) != nil }) + let _ = b.finalize() + } + } + + func testArrayGetSchedulingTest() { + let fuzzer = makeMockFuzzer() + let numPrograms = 30 + + for _ in 0..( + _ generatorName: String, + expectAny: repeat (each ExpectedOp).Type, + requiresTypes: Bool = false + ) { + let fuzzer = makeMockFuzzer() + let numPrograms = 30 + + for _ in 0.. 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) + } 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) + } + + // 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) + } + +} 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 887f0e1e9..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,28 @@ 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) } +class TestUtilsTests: XCTestCase { + + // Test that running a program via the JavaScriptExecutor that produces a large output succeeds. + // (This test case exists because when using a raw Pipe() as stdout without any further + // handling, the child process will be interrupted once the buffer size (64KB on Linux + // apparently) is filled.) + func testJavaScriptExecutorLargeOutput() throws { + let jsProg = "console.log(JSON.stringify(Array(50000).fill(1)))" + let runner = try GetJavaScriptExecutorOrSkipTest() + let result = try runner.executeScript(jsProg, withTimeout: 10) + XCTAssert(result.isSuccess, "\(result.output)\n\(result.error)") + XCTAssertGreaterThan(result.output.count, 100_000) + } +} diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 5e6f0fd77..5833233e6 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,59 +1236,87 @@ 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 nullExn = ILType.wasmRef(.Abstract(.WasmExn), nullability: true) - let nonNullAny = ILType.wasmRef(.Abstract(.WasmAny), nullability: false) - XCTAssertEqual(nullExn.description, ".wasmRef(.Abstract(null WasmExn))") + 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) + XCTAssertEqual(nullExn.description, ".wasmRef(.Abstract(null shared WasmExn))") XCTAssertEqual(nonNullAny.description, ".wasmRef(.Abstract(WasmAny))") - let arrayDesc = WasmArrayTypeDescription(elementType: .wasmi32, mutability: false, typeGroupIndex: 0) + // TODO(pawkra): add shared variant. + 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], 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 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 @@ -1163,7 +1327,8 @@ class TypeSystemTests: XCTestCase { } func testWasmSubsumptionRules() { - let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmFuncRef, .wasmExternRef, .wasmI31Ref, .wasmExnRef] + 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) @@ -1171,52 +1336,76 @@ 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)) // Test nullability rules for abstract Wasm types. for heapType: WasmAbstractHeapType in WasmAbstractHeapType.allCases { - let nullable = ILType.wasmRef(.Abstract(heapType), nullability: true) - let nonNullable = ILType.wasmRef(.Abstract(heapType), nullability: false) - XCTAssert(nonNullable.Is(nullable)) - XCTAssertFalse(nullable.Is(nonNullable)) - XCTAssertEqual(nullable.union(with: nonNullable), nullable) - XCTAssertEqual(nonNullable.union(with: nullable), nullable) - XCTAssertEqual(nullable.intersection(with: nonNullable), nonNullable) - XCTAssertEqual(nonNullable.intersection(with: nullable), nonNullable) + for shared in [true, false] { + let nullable = ILType.wasmRef(heapType, shared: shared, nullability: true) + let nonNullable = ILType.wasmRef(heapType, shared: shared, nullability: false) + XCTAssert(nonNullable.Is(nullable)) + XCTAssertFalse(nullable.Is(nonNullable)) + XCTAssertEqual(nullable.union(with: nonNullable), nullable) + XCTAssertEqual(nonNullable.union(with: nullable), nullable) + XCTAssertEqual(nullable.intersection(with: nonNullable), nonNullable) + XCTAssertEqual(nonNullable.intersection(with: nullable), nonNullable) + } } } @@ -1251,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 { @@ -1276,7 +1465,6 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(type.intersection(type.getBottom()), type.getBottom()) } - // Testing a few combinations. XCTAssertEqual(WasmAbstractHeapType.WasmAny.union(.WasmEq), .WasmAny) XCTAssertEqual(WasmAbstractHeapType.WasmStruct.union(.WasmArray), .WasmEq) XCTAssertEqual(WasmAbstractHeapType.WasmI31.union(.WasmArray), .WasmEq) @@ -1287,35 +1475,52 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(WasmAbstractHeapType.WasmAny.intersection(.WasmArray), .WasmArray) // Tests on the whole ILType. - let ref = {t in ILType.wasmRef(.Abstract(t), nullability: false)} - let refNull = {t in ILType.wasmRef(.Abstract(t), nullability: true)} - for type in allTypes { - let refT = ref(type) - let refNullT = refNull(type) - XCTAssertEqual(refT.union(with: refNullT), refNullT) - XCTAssertEqual(refNullT.union(with: refT), refNullT) - XCTAssertEqual(refT.union(with: refT), refT) - XCTAssertEqual(refNullT.union(with: refNullT), refNullT) - XCTAssertEqual(refT.intersection(with: refT), refT) - XCTAssertEqual(refNullT.intersection(with: refNullT), refNullT) - XCTAssertEqual(refT.intersection(with: refNullT), refT) - XCTAssertEqual(refNullT.intersection(with: refT), refT) + 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) } + + for type in allTypes { + let refT = ref(type) + let refNullT = refNull(type) + XCTAssertEqual(refT.union(with: refNullT), refNullT) + XCTAssertEqual(refNullT.union(with: refT), refNullT) + XCTAssertEqual(refT.union(with: refT), refT) + XCTAssertEqual(refNullT.union(with: refNullT), refNullT) + XCTAssertEqual(refT.intersection(with: refT), refT) + XCTAssertEqual(refNullT.intersection(with: refNullT), refNullT) + XCTAssertEqual(refT.intersection(with: refNullT), refT) + XCTAssertEqual(refNullT.intersection(with: refT), refT) + } + XCTAssertEqual(ref(.WasmAny).union(with: refNull(.WasmEq)), refNull(.WasmAny)) + XCTAssertEqual(ref(.WasmStruct).union(with: ref(.WasmArray)), ref(.WasmEq)) + // We should never do this for the type information of any Variable as .wasmGenericRef + // cannot be encoded in the Wasm module and any instruction that leads to such a static type + // is "broken". However, we will still need to allow this union type if we want to be able + // to request a .required(.wasmGenericRef) for operations like WasmRefIsNull. + 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)) + // 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)) } - XCTAssertEqual(ref(.WasmAny).union(with: refNull(.WasmEq)), refNull(.WasmAny)) - XCTAssertEqual(ref(.WasmStruct).union(with: ref(.WasmArray)), ref(.WasmEq)) - // We should never do this for the type information of any Variable as .wasmGenericRef - // cannot be encoded in the Wasm module and any instruction that leads to such a static type - // is "broken". However, we will still need to allow this union type if we want to be able - // to request a .required(.wasmGenericRef) for operations like WasmRefIsNull. - 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)) - // 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) } + // 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) + } + } } func testUnboundFunctionSubsumptionRules() { @@ -1324,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()) @@ -1341,107 +1548,143 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(receiverObject.intersection(with: receiverNil), receiverObject) } - let primitiveTypes: [ILType] = [.undefined, .integer, .float, .string, .boolean, .bigint, .regexp] + 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, + ] // 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, - .wasmFuncRef, - .wasmExternRef, - .wasmExnRef, - .wasmI31Ref, - .wasmRefI31, - .wasmFunctionDef([.wasmi32] => [.wasmi64]), - .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef] => [.wasmExternRef]), - .wasmMemory(limits: Limits(min: 10)), - .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + 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 c3e59c9b7..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) @@ -31,7 +33,7 @@ class WasmTableTests: XCTestCase { expectedOutput += "10\n" wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { f, _, _ in - let initialValue = f.wasmRefNull(type: .wasmFuncRef) + let initialValue = f.wasmRefNull(type: .wasmFuncRef()) let growBy = f.consti32(5) let oldSize = f.wasmTableGrow(table: table, with: initialValue, by: growBy) let newSize = f.wasmTableSize(table: table) diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 05a3c6b61..d18ecef71 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(.Abstract(.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") @@ -324,28 +411,36 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let ctr = function.consti32(10) - function.wasmBuildLoop(with: [] => []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + function.wasmBuildLoop(with: [] => [], args: []) { label, args in + 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. let isNotZero = function.wasmi32CompareOp(ctr, function.consti32(0), using: .Ne) function.wasmBranchIf(isNotZero, to: label) + return [] } return [ctr] } let tag = wasmModule.addTag(parameterTypes: [.wasmi32, .wasmi32]) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { _, _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123), function.consti32(456)]) - function.WasmBuildLegacyCatch(tag: tag) { _, _, 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") @@ -441,7 +541,7 @@ class WasmFoundationTests: XCTestCase { } func testGlobalExnRef() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) @@ -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: ILType.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,12 +564,16 @@ 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 [] } - return [function.wasmRefNull(type: .wasmExnRef)] + return [function.wasmRefNull(type: .wasmExnRef())] }[0] function.wasmStoreGlobal(globalVariable: global, to: exnref) return [] @@ -473,12 +581,17 @@ 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)] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] } return [caughtValues[0]] } @@ -509,12 +622,17 @@ 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)] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] } return [caughtValues[0]] } @@ -538,13 +656,17 @@ 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: ILType.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 + wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmExternRef] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmExternRef()] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -577,8 +699,13 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() + // 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). @@ -603,13 +730,17 @@ 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: ILType.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 + wasmModule.addWasmFunction(with: [] => [.wasmI31Ref()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmI31Ref] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmI31Ref()] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -641,8 +772,13 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() + // 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). @@ -666,18 +802,27 @@ 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 + wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, _, _ in let offset = isTable64 ? function.consti64(0) : function.consti32(0) var ref = function.wasmTableGet(tableRef: tableRef, idx: offset) let offset1 = isTable64 ? function.consti64(1) : function.consti32(1) @@ -694,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) @@ -724,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: []) @@ -790,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]) } } @@ -840,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]] } } @@ -881,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) @@ -904,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() @@ -923,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)] } @@ -962,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)] } } @@ -994,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)] } } @@ -1042,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)]) @@ -1100,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") @@ -1133,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! @@ -1142,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 @@ -1167,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]) @@ -1183,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]) @@ -1201,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! @@ -1211,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 @@ -1236,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! @@ -1246,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 { @@ -1273,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! @@ -1283,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 { @@ -1304,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! @@ -1314,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 { @@ -1332,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. @@ -1347,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. @@ -1377,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] } } @@ -1385,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 [] } } @@ -1432,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) @@ -1482,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) @@ -1503,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), @@ -1523,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()) @@ -1557,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 { @@ -1582,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) @@ -1601,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") @@ -1634,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 @@ -1898,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) } @@ -1915,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()) @@ -1927,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] @@ -2011,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) } } @@ -2641,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) } @@ -2684,14 +3741,16 @@ class WasmFoundationTests: XCTestCase { let max = function.consti32(10) let one = function.consti32(1) - function.wasmBuildLoop(with: [] => []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + function.wasmBuildLoop(with: [] => [], args: []) { label, args in + 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) + 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) function.wasmBranchIf(comp, to: label) + return [] } // Now combine the result of the break and the loop into one and return it. @@ -2719,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), hint: .None) { + 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() @@ -2753,18 +3820,18 @@ 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) - function.wasmBuildIfElse(comp, hint: .None, ifBody: { + function.wasmBuildIfElse(comp) { label, args in let tmp = function.wasmi32BinOp(variable, condVariable, binOpKind: .Add) function.wasmReassign(variable: result, to: tmp) - }, elseBody: { + } elseBody: { label, args in let tmp = function.wasmi32BinOp(variable, condVariable, binOpKind: .Sub) function.wasmReassign(variable: result, to: tmp) - }) + } return [result] } @@ -2772,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)]) @@ -2789,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)] } @@ -2802,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() @@ -2819,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)) } @@ -2834,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) @@ -2857,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) @@ -2867,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() @@ -2894,12 +3976,14 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { - let one = function.wasmJsCall(function: jsReturnOne, withArgs: [], + _, _ in + let one = function.wasmJsCall( + function: jsReturnOne, withArgs: [], withWasmSignature: [] => [.wasmi32])! function.wasmReturn(one) } let cond = function.wasmi32CompareOp(args[0], function.consti32(4), using: .Gt_s) - function.wasmBuildIfElse(cond, hint: .Likely) { + function.wasmBuildIfElse(cond, hint: .Likely) { _, _ in function.wasmReturn(function.consti32(2)) } function.wasmBranchIf( @@ -2909,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() @@ -2934,8 +4022,8 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - XCTAssert(b.type(of: label).Is(.anyLabel)) + function.wasmBuildLegacyTryVoid { label in + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) function.wasmReturn(function.consti64(42)) } return [function.consti64(-1)] @@ -2967,11 +4055,13 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - XCTAssert(b.type(of: label).Is(.anyLabel)) + function.wasmBuildLegacyTryVoid { label in + 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([])) - 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)) @@ -3010,17 +4100,26 @@ class WasmFoundationTests: XCTestCase { b.buildIfElse(supportsJSTag) { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { 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() - function.WasmBuildLegacyCatch(tag: jstag) { 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(.anyWasmLabel)) + 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)] } @@ -3066,20 +4165,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - XCTAssert(b.type(of: label).Is(.anyLabel)) - function.WasmBuildThrow(tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) - function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: otherTag) { label, exception, args in + function.wasmBuildLegacyTryVoid( + body: { label in + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) + function.WasmBuildThrow( + tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) function.wasmUnreachable() - } - function.WasmBuildLegacyCatch(tag: throwTag) { 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() - } + }, + 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() + }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3102,12 +4214,18 @@ class WasmFoundationTests: XCTestCase { let tag = b.createWasmTag(parameterTypes: []) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { tryLabel, _ in - function.WasmBuildThrow(tag: tag, inputs: []) - function.WasmBuildLegacyCatch(tag: tag) { catchLabel, exceptionLabel, args in - function.wasmBranch(to: catchLabel) - } - } + function.wasmBuildLegacyTryVoid( + body: { tryLabel in + function.WasmBuildThrow(tag: tag, inputs: []) + }, + catchClauses: [ + ( + tag: tag, + body: { catchLabel, wasmExceptionLabel, args in + function.wasmBranch(to: catchLabel) + } + ) + ]) return [function.consti32(42)] } } @@ -3130,7 +4248,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in function.wasmBuildBlock(with: [] => [], args: []) { blockLabel, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { tryLabel, _ in + function.wasmBuildLegacyTryVoid { tryLabel in function.WasmBuildThrow(tag: tag, inputs: []) } catchAllBody: { label in function.wasmBranch(to: blockLabel) @@ -3149,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) @@ -3185,22 +4302,37 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, param in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmBuildIfElse(param[0], hint: .None) { - function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) - } elseBody: { - function.WasmBuildThrow(tag: importedTag, inputs: [function.consti32(123)]) - } - function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: importedTag) { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(1), binOpKind: .Add)) - } - function.WasmBuildLegacyCatch(tag: definedTag) { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(4), binOpKind: .Add)) - } - } catchAllBody: { label in - function.wasmUnreachable() - } + 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() + }) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3236,16 +4368,30 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in let argI32 = function.consti32(123) let argI64 = function.consti64(321) - function.wasmBuildLegacyTry(with: [.wasmi64, .wasmi32] => [], args: [argI64, argI32]) { 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) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - let result = function.wasmi64BinOp(args[0], function.extendi32Toi64(args[1], isSigned: true), binOpKind: .Add) - function.wasmReturn(result) - } - } + 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(.anyWasmLabel)) + 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)] } @@ -3275,30 +4421,51 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in let contant42 = function.consti64(42) - let result = function.wasmBuildLegacyTryWithResult(with: [.wasmi32] => [.wasmi32, .wasmi64], args: args, body: { label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .None) { - function.WasmBuildThrow(tag: tagVoid, inputs: []) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq), hint: .None) { - function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(100)]) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq), hint: .None) { - function.WasmBuildThrow(tag: tagi32Other, inputs: [function.consti32(200)]) - } - return [args[0], contant42] - }, catchClauses: [ - (tagi32, {label, exception, args in + 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] - }), - (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) { + }, + 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]] @@ -3311,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" } @@ -3362,23 +4531,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { 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.wasmBuildLegacyTry(with: [] => [], args: []) { 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.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() - } - function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: tag) { 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)] } @@ -3403,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)] @@ -3448,18 +4630,30 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmBuildLegacyRethrow(exception) - } - } - function.WasmBuildLegacyCatch(tag: tag) { 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)] } @@ -3501,26 +4695,46 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - function.WasmBuildLegacyCatch(tag: tag) { label, outerException, args in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(456)]) - function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: tag) { label, innerException, args in - // There are two "active" exceptions: - // outerException: [123: i32] - // innerException: [456: i32] - function.wasmBuildLegacyRethrow(outerException) - } + 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.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmReturn(args[0]) - } - } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3544,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() @@ -3570,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] } @@ -3595,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() @@ -3633,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() @@ -3652,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)]) } @@ -3685,27 +4933,35 @@ class WasmFoundationTests: XCTestCase { } func testTryTableNoCatch() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() 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() @@ -3714,7 +4970,7 @@ class WasmFoundationTests: XCTestCase { } func testTryTable() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -3724,11 +4980,16 @@ 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 - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .None) { + 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: { + } elseBody: { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) } return [] @@ -3742,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() @@ -3753,7 +5016,7 @@ class WasmFoundationTests: XCTestCase { } func testTryTableRef() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -3762,29 +5025,37 @@ 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.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .None) { + 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: { + } elseBody: { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) } return [] } - return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef)] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] } function.wasmReturn(catchRefI32[0]) - return [function.wasmRefNull(type: .wasmExnRef)] + return [function.wasmRefNull(type: .wasmExnRef())] } return [function.consti32(100)] } } 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() @@ -3793,7 +5064,7 @@ class WasmFoundationTests: XCTestCase { } func tagExportedToDifferentWasmModule(defineInWasm: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -3801,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 [] } } @@ -3819,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)] @@ -3861,13 +5143,13 @@ class WasmFoundationTests: XCTestCase { // Test that defining a Wasm tag in JS with all supported abstract ref types does not fail. func testTagAllRefTypesInJS() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - // Assumption: All types but the bottom (null) types are supported in the JS API. - let supportedTypes = WasmAbstractHeapType.allCases.filter {!$0.isBottom()}.map { heapType in - ILType.wasmRef(.Abstract(heapType), nullability:true) + // 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) } b.createWasmTag(parameterTypes: supportedTypes) let prog = b.finalize() @@ -3880,7 +5162,7 @@ class WasmFoundationTests: XCTestCase { } func testThrowRef() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -3893,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)] + 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 [] @@ -3910,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)] @@ -3922,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) @@ -3968,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])] } } @@ -3980,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() @@ -4009,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))] } @@ -4018,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() @@ -4031,33 +5339,42 @@ class WasmFoundationTests: XCTestCase { // This test covers a bug where imported functions were not accounted for correctly when // lifting a direct call to a non-imported wasm function. func testCallDirectJSCall() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() 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) @@ -4077,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])! + ] } } @@ -4086,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() @@ -4112,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]) @@ -4127,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) @@ -4143,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)]} - - module.addTable(elementType: .wasmFuncRef, + 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(), minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef, + let table2 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], @@ -4163,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 callIndirect = { (table: Variable, idx: Int) 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 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 { @@ -4190,38 +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)] + } - let table1 = module.addTable(elementType: .wasmFuncRef, + // TODO(pawkra): add shared ref variant. + 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 callIndirect = { (table: Variable, idx: Int) 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 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 { @@ -4242,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() @@ -4284,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), ] } } @@ -4326,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] } @@ -4338,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() @@ -4358,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), @@ -4370,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() @@ -4385,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] @@ -4398,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() @@ -4414,6 +5806,50 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n") } + func testStructNew() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) + let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) + 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]) + return [structOfi32, structOfStruct] + } + let structOfi32 = types[0] + let structOfStruct = types[1] + + 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) + 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)]) + b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) + + let program = b.finalize() + let jsProgram = fuzzer.lifter.lift(program) + testForOutput(program: jsProgram, runner: runner, outputString: "42\n") + } + func testStructPacked() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -4421,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), @@ -4452,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 { @@ -4462,14 +5906,16 @@ 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] } + // TODO(pawkra): add shared ref variant. let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [] => [.wasmFuncRef]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [.wasmFuncRef()]) { function, label, args in // TODO(mliedtke): Do something more useful with the signature type than // defining a null value for it and testing that it's implicitly convertible to // .wasmFuncRef. @@ -4489,6 +5935,93 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\n") } + func testLoopWithWasmGCSignature() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + let jsProg = buildAndLiftProgram { b in + + let typeGroup = b.wasmDefineTypeGroup { + let arrayType = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) + let signature = b.wasmDefineSignatureType( + signature: [.wasmRef(.Index(), nullability: true)] + => [.wasmRef(.Index(), nullability: true)], + indexTypes: [arrayType, arrayType]) + return [arrayType, signature] + } + let arrayType = typeGroup[0] + let loopSignature = typeGroup[1] + + 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, + elements: [function.consti32(1)]) + 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) + function.wasmBranchIf(cond, to: loopLabel, args: [args[0]]) + return args + }[0] + return [function.wasmArrayGet(array: arrayResult, index: index)] + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: []) + b.callFunction(outputFunc, withArgs: [wasmOut]) + } + + testForOutput(program: jsProg, runner: runner, outputString: "64\n") + } + + func testLoopWithAdHocWasmGCSignature() throws { + 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 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)) + 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 + 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) + function.wasmBranchIf(cond, to: loopLabel, args: [newStruct]) + return [newVal] + } + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: []) + b.callFunction(outputFunc, withArgs: [wasmOut]) + } + + testForOutput(program: jsProg, runner: runner, outputString: "64\n") + } + func testSelfReferenceType() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -4497,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() @@ -4533,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] @@ -4541,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() @@ -4569,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] } @@ -4599,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() @@ -4629,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] } @@ -4638,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] } @@ -4660,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 @@ -4685,15 +6246,21 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n") } - func testRefNullAbstractTypes() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) + func refNullAbstractTypes(sharedRef: Bool) throws { + 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 module = b.buildWasmModule { wasmModule in - for heapType in WasmAbstractHeapType.allCases { - let valueType = ILType.wasmRef(.Abstract(heapType), nullability: true) + for heapType in supportedHeapTypes { + let valueType = ILType.wasmRef(heapType, shared: sharedRef, nullability: true) if heapType.isUsableInJS() { // ref.null wasmModule.addWasmFunction(with: [] => [valueType]) { function, label, args in @@ -4709,8 +6276,9 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let exportedFctCount = WasmAbstractHeapType.allCases.count - + WasmAbstractHeapType.allCases.count {$0.isUsableInJS()} + let exportedFctCount = + supportedHeapTypes.count + + supportedHeapTypes.count { $0.isUsableInJS() } for i in 0.. [.wasmI31Ref]) { function, label, args in - [function.wasmRefI31(args[0])] + wasmModule.addWasmFunction(with: [.wasmEqRef(), .wasmEqRef()] => [.wasmi32]) { + function, label, args in + return [function.wasmRefEq(args[0], args[1])] } - wasmModule.addWasmFunction(with: [.wasmI31Ref] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true), - function.wasmI31Get(args[0], isSigned: false)] + wasmModule.addWasmFunction(with: [] => [.wasmEqRef()]) { function, label, args in + return [function.wasmArrayNewFixed(arrayType: arrayType, elements: [])] + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + + let array = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: []) + let otherArray = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: []) + + let wasmRefEq = module.getExportedMethod(at: 0) + let cases = [ + 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]), + ] + + for input in cases { b.callFunction(outputFunc, withArgs: [input]) } + + let prog = b.finalize() + let jsProg = fuzzer.lifter.lift(prog) + testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n1\n0\n") + } + + func i31Ref(shared: Bool) throws { + 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 i31RefT = ILType.wasmI31Ref(shared: shared) + + let module = b.buildWasmModule { wasmModule in + 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), + ] } } 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 { + try i31Ref(shared: true) + } + + func testi31RefUnshared() throws { + try i31Ref(shared: false) } func testExternAnyConversions() throws { @@ -4764,29 +6399,33 @@ 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])) - XCTAssertEqual(b.type(of: result), .wasmRefExtern) + XCTAssertEqual(b.type(of: result), .wasmRefExtern()) 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) + XCTAssertEqual(b.type(of: result), .wasmRefAny()) return [result] } - wasmModule.addWasmFunction(with: [] => [.wasmExternRef]) { function, label, args in - let result = function.wasmExternConvertAny(function.wasmRefNull(type: .wasmNullRef)) - XCTAssertEqual(b.type(of: result), .wasmExternRef) + wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in + 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)) - XCTAssertEqual(b.type(of: result), .wasmAnyRef) + wasmModule.addWasmFunction(with: [] => [.wasmAnyRef()]) { function, label, args in + let result = function.wasmAnyConvertExtern( + function.wasmRefNull(type: .wasmNullExternRef())) + XCTAssertEqual(b.type(of: result), .wasmAnyRef()) return [result] } } @@ -4794,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]) } @@ -4802,6 +6442,167 @@ class WasmGCTests: XCTestCase { let jsProg = fuzzer.lifter.lift(prog) testForOutput(program: jsProg, runner: runner, outputString: "42\n42\nnull\nnull\n") } + + func testRefTest() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) + let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) + let b = fuzzer.makeBuilder() + + let arrayType = b.wasmDefineTypeGroup { + b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) + }[0] + let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) + + let module = b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in + let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: []) + let null = function.wasmRefNull(type: .wasmArrayRef()) + let refType = ILType.wasmRef(.Index(), nullability: false) + let refNullType = ILType.wasmRef(.Index(), nullability: true) + let results = [ + function.wasmRefTest(array, refType: refType, typeDef: arrayType), + function.wasmRefTest(null, refType: refType, typeDef: arrayType), + 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) + }) + return [result] + } + wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in + let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: []) + let result = function.wasmRefTest(array, refType: .wasmEqRef()) + return [result] + } + wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in + let ref = function.wasmRefI31(function.consti32(0)) + let refType = ILType.wasmRef(.Index(), nullability: false) + let result = function.wasmRefTest(ref, refType: refType, typeDef: arrayType) + return [result] + } + 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 + function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(42)]) + return [] + } + return [function.wasmRefNull(type: .wasmExnRef())] + }[0] + let result = function.wasmRefTest(exnref, refType: .wasmExnRef()) + return [result] + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + for method in module.getExportedMethods() { + let result = b.callMethod(method.0, on: exports, withArgs: [b.loadInt(42)]) + b.callFunction(outputFunc, withArgs: [result]) + } + + let prog = b.finalize() + let jsProg = fuzzer.lifter.lift(prog) + testForOutput(program: jsProg, runner: runner, outputString: "1011\n1\n0\n0\n1\n") + } + + func testRefCast() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) + let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) + let b = fuzzer.makeBuilder() + + 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 + let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: [args[0]]) + return [array] + } + 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), + ) + let arrays = [ + function.wasmRefCast(args[0], refType: refType, typeDef: arrayType), + function.wasmRefCast(args[0], refType: nonNullRefType, typeDef: arrayType), + function.wasmRefCast(args[0], refType: abstractRefType), + ] + 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) + ] + } + wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmRefExtern()]) { + function, label, args in + let cast = function.wasmRefCast(args[0], refType: .wasmRefExtern()) + return [cast] + } + } + + 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]) + b.callFunction(outputFunc, withArgs: [result]) + let ext = b.callMethod( + module.getExportedMethod(at: 2), on: exports, withArgs: [b.loadInt(5)]) + b.callFunction(outputFunc, withArgs: [ext]) + + let prog = b.finalize() + let jsProg = fuzzer.lifter.lift(prog) + testForOutput(program: jsProg, runner: runner, outputString: "42\n5\n") + } + + func testRefCastError() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + 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 cast = function.wasmRefCast(funcref, refType: nullFuncType) + return [cast] + } + } + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + + b.buildTryCatchFinally { + let _ = b.callMethod(module.getExportedMethod(at: 0), on: exports) + b.callFunction(outputFunc, withArgs: [b.loadString("Not reached")]) + } catchBody: { e in + b.callFunction(outputFunc, withArgs: [b.loadString("exception")]) + } + } + testForOutput(program: jsProg, runner: runner, outputString: "exception\n") + } } class WasmNumericalTests: XCTestCase { @@ -4818,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)] } } @@ -4914,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)] } } @@ -5010,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)] } } @@ -5022,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") @@ -5074,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)] } } @@ -5086,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") @@ -5139,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)] } } @@ -5186,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)] } } @@ -5234,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)] } } @@ -5297,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)] } } @@ -5361,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)] } } @@ -5452,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)] } } @@ -5544,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)] } } @@ -5603,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)] } } @@ -6029,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) @@ -6074,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" @@ -6092,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) @@ -6225,8 +8040,10 @@ 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)])) - splicePoint = b.indexOfNextInstruction() + 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) return [] } @@ -6269,8 +8086,10 @@ 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)])) - splicePoint = b.indexOfNextInstruction() + 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) return [] } @@ -6300,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 [] } @@ -6315,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) @@ -6327,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)) } @@ -6337,8 +8160,12 @@ 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])!] + m.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32]) { f, label, args in + [ + f.wasmJsCall( + function: importFunction, withArgs: args, + withWasmSignature: [.wasmExternRef()] => [.wasmi32])! + ] } } @@ -6377,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. diff --git a/Tools/presubmit.py b/Tools/presubmit.py old mode 100644 new mode 100755 index df04798e6..cf59ac292 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -1,3 +1,20 @@ +#!/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 argparse import os import shutil import subprocess @@ -5,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", @@ -13,23 +31,22 @@ "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"], cwd=BASE_DIR, capture_output=True, check=True) - assert result.stdout.decode().strip() == "", f"Unexpected modified files: {result.stdout.decode()}" + 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 {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() +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 @@ -43,14 +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. - check_git_clean() + 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 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() - check_proto() - # TODO(mliedtke): Ensure formatting delta is zero once we enable automated 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__': diff --git a/Tools/transpile_tests/.gitignore b/Tools/transpile_tests/.gitignore new file mode 100644 index 000000000..7e99e367f --- /dev/null +++ b/Tools/transpile_tests/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/Tools/transpile_tests/.vpython3 b/Tools/transpile_tests/.vpython3 new file mode 100644 index 000000000..f683b68bc --- /dev/null +++ b/Tools/transpile_tests/.vpython3 @@ -0,0 +1,21 @@ +python_version: "3.11" + +wheel: < + name: "infra/python/wheels/six-py2_py3" + version: "version:1.16.0" +> + +wheel: < + name: "infra/python/wheels/pbr-py2_py3" + version: "version:3.0.0" +> + +wheel: < + name: "infra/python/wheels/mock-py2_py3" + version: "version:2.0.0" +> + +wheel: < + name: "infra/python/wheels/pyfakefs-py3" + version: "version:5.7.3" +> \ No newline at end of file diff --git a/Tools/transpile_tests/PRESUBMIT.py b/Tools/transpile_tests/PRESUBMIT.py new file mode 100644 index 000000000..cea2e358f --- /dev/null +++ b/Tools/transpile_tests/PRESUBMIT.py @@ -0,0 +1,34 @@ +# 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. + +USE_PYTHON3 = True + + +def _CommonChecks(input_api, output_api): + return input_api.RunTests( + input_api.canned_checks.GetUnitTestsRecursively( + input_api, + output_api, + input_api.os_path.join(input_api.PresubmitLocalPath()), + files_to_check=[r'test.+\.py$'], + files_to_skip=[], + run_on_python2=False, + )) + + +def CheckChangeOnUpload(input_api, output_api): + return _CommonChecks(input_api, output_api) + +def CheckChangeOnCommit(input_api, output_api): + return _CommonChecks(input_api, output_api) diff --git a/Tools/transpile_tests/merge_json_results.py b/Tools/transpile_tests/merge_json_results.py new file mode 100644 index 000000000..0b0a38fab --- /dev/null +++ b/Tools/transpile_tests/merge_json_results.py @@ -0,0 +1,68 @@ +# 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. + +""" +Script to merge multiple output json files from transpile_tests.py into one. +""" + +import argparse +import json +import sys + +from collections import defaultdict, Counter + + +def merge_test_results(inputs): + num_tests = Counter() + failures = defaultdict(list) + + for result in inputs: + for key, value in result.items(): + num_tests[key] += value["num_tests"] + failures[key] += value["failures"] + + return dict( + (key, {'num_tests': num_tests[key], 'failures': failures[key]}) + for key in sorted(num_tests.keys()) + ) + + +def parse_args(args): + parser = argparse.ArgumentParser() + parser.add_argument( + '--json-input', action='append', required=True, + help='Path to a json results file from transpile_tests.py.') + parser.add_argument( + '--json-output', required=True, + help='Path to the merged json results file.') + return parser.parse_args(args) + + +def main(args): + options = parse_args(args) + + inputs = [] + for input_path in options.json_input: + with open(input_path) as f: + inputs.append(json.load(f)) + + result = merge_test_results(inputs) + with open(options.json_output, 'w') as f: + json.dump(result, f, sort_keys=True, indent=2) + + print(f'Successfully merged results.') + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/Tools/transpile_tests/test_merge_json_results.py b/Tools/transpile_tests/test_merge_json_results.py new file mode 100644 index 000000000..a297172f2 --- /dev/null +++ b/Tools/transpile_tests/test_merge_json_results.py @@ -0,0 +1,104 @@ +# 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 contextlib +import io +import json +import unittest + +from pyfakefs import fake_filesystem_unittest + +import merge_json_results + + +class TestMergeResults(fake_filesystem_unittest.TestCase): + + @fake_filesystem_unittest.patchfs(allow_root_user=True) + def test_full_run(self, fs): + with open('/in1.json', 'w') as f: + json.dump({ + 'a/a': { + 'num_tests': 2, + 'failures': [], + }, + 'a/b': { + 'num_tests': 2, + 'failures': [ + {'path': 'a/b/c/failure1', 'output': 'foo'}, + ], + }, + }, f) + + with open('/in2.json', 'w') as f: + json.dump({ + 'a': { + 'num_tests': 1, + 'failures': [ + {'path': 'a/failure4', 'output': 'foo'}, + ], + }, + 'a/a': { + 'num_tests': 1, + 'failures': [], + }, + 'a/b': { + 'num_tests': 3, + 'failures': [ + {'path': 'a/b/c/failure2', 'output': 'bar 42\nbar 43'}, + {'path': 'a/b/d/failure3', 'output': 'baz'}, + ] + }, + }, f) + + f = io.StringIO() + with contextlib.redirect_stdout(f): + merge_json_results.main([ + '--json-input', '/in1.json', + '--json-input', '/in2.json', + '--json-output', '/output.json', + ]) + + # Verify the output. + self.assertEqual( + 'Successfully merged results.', + f.getvalue().strip()) + + # Verify the results written to the json output file. + with open('/output.json') as f: + actual_results = json.load(f) + + expected_results = { + 'a': { + 'failures': [{'output': 'foo', 'path': 'a/failure4'}], + 'num_tests': 1, + }, + 'a/a': { + 'failures': [], + 'num_tests': 3, + }, + 'a/b': { + 'failures': [ + {'output': 'foo', 'path': 'a/b/c/failure1'}, + {'output': 'bar 42\nbar 43', 'path': 'a/b/c/failure2'}, + {'output': 'baz', 'path': 'a/b/d/failure3'}, + ], + 'num_tests': 5, + }, + } + + self.assertEqual(expected_results, actual_results) + + +if __name__ == '__main__': + unittest.main() diff --git a/Tools/transpile_tests/test_transpile_tests.py b/Tools/transpile_tests/test_transpile_tests.py new file mode 100644 index 000000000..a388763ec --- /dev/null +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -0,0 +1,316 @@ +# 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 contextlib +import glob +import io +import json +import os +import unittest + +from collections import namedtuple +from mock import patch +from pathlib import Path +from pyfakefs import fake_filesystem_unittest + +import transpile_tests + + +TEST_DATA = Path(__file__).parent / 'testdata' + + +# Mock out the FuzzIL tool, but mimick writing the desired output file. +# Simulate one compilation failure for the test with "fail" in its name. +Process = namedtuple('Process', 'returncode stdout') +def fake_transpile(input_file, output_file): + if 'fail' in str(output_file): + return Process(1, 'Failed!'.encode('utf-8')) + with open(output_file, 'w') as f: + f.write('') + return Process(0, b'') + + +# Replace the multiprocessing Pool with a fake that doesn't mess with the +# fake file system. +class FakePool: + def __init__(self, _): + pass + + def __enter__(self): + return self + + def __exit__(self, *_): + pass + + def imap_unordered(self, *args): + return map(*args) + + +class TestTranspileTests(fake_filesystem_unittest.TestCase): + + @fake_filesystem_unittest.patchfs(allow_root_user=True) + def test_full_run(self, fs): + base_dir = TEST_DATA / 'transpile_full_run' / 'v8' + fs.create_dir('/output') + fs.add_real_directory(base_dir) + + f = io.StringIO() + with contextlib.redirect_stdout(f): + with patch( + 'transpile_tests.run_transpile_tool', fake_transpile): + with patch( + 'multiprocessing.Pool', FakePool): + transpile_tests.main([ + '--config', 'test262', + '--base-dir', str(base_dir), + '--output-dir', '/output', + '--json-output', '/output.json', + ]) + + # Verify the output. + self.assertEqual( + 'Successfully compiled 75.00% (3 of 4) test cases.', + f.getvalue().strip()) + + # Verify the written output files. + expected_files = [ + '/output/test/test262/data/test/folder1/subfolder1/Test1.js', + '/output/test/test262/data/test/folder1/subfolder1/Test2.js', + '/output/test/test262/data/test/folder2/Test3.js', + ] + self.assertEqual( + expected_files, glob.glob('/output/**/*.*', recursive=True)) + + # Verify the results written to the json output file. + with open('/output.json') as f: + actual_results = json.load(f) + + expected_results = { + 'folder1/subfolder1': { + 'failures': [], + 'num_tests': 2, + }, + 'folder2': { + 'failures': [{'output': 'Failed!', 'path': 'folder2/Test4_fail.js'}], + 'num_tests': 2, + }, + } + self.assertEqual(expected_results, actual_results) + + @fake_filesystem_unittest.patchfs(allow_root_user=True) + def test_shard_run(self, fs): + base_dir = TEST_DATA / 'transpile_full_run' / 'v8' + fs.create_dir('/output') + fs.add_real_directory(base_dir) + + f = io.StringIO() + with contextlib.redirect_stdout(f): + with patch( + 'transpile_tests.run_transpile_tool', fake_transpile): + with patch( + 'multiprocessing.Pool', FakePool): + transpile_tests.main([ + '--config', 'test262', + '--base-dir', str(base_dir), + '--output-dir', '/output', + '--json-output', '/output.json', + '--num-shards', '2', + '--shard-index', '1', + ]) + + # Verify the output. + self.assertEqual( + 'Successfully compiled 50.00% (1 of 2) test cases.', + f.getvalue().strip()) + + # Verify the written output files. + expected_files = [ + '/output/test/test262/data/test/folder1/subfolder1/Test2.js', + ] + self.assertEqual( + expected_files, glob.glob('/output/**/*.*', recursive=True)) + + # Verify the results written to the json output file. + with open('/output.json') as f: + actual_results = json.load(f) + + expected_results = { + 'folder1/subfolder1': { + 'failures': [], + 'num_tests': 1, + }, + 'folder2': { + 'failures': [{'output': 'Failed!', 'path': 'folder2/Test4_fail.js'}], + 'num_tests': 1, + }, + } + self.assertEqual(expected_results, actual_results) + + +Options = namedtuple('Options', 'verbose') + +class UnitTests(unittest.TestCase): + def test_level_key_0(self): + counter = transpile_tests.TestCounter(0, [], Options(False)) + self.assertEqual('', counter.level_key(Path('test.js'))) + self.assertEqual('', counter.level_key(Path('level1/test.js'))) + + def test_level_key_2(self): + counter = transpile_tests.TestCounter(2, [], Options(False)) + self.assertEqual( + '', counter.level_key(Path('test.js'))) + self.assertEqual( + 'level1', counter.level_key(Path('level1/test.js'))) + self.assertEqual( + 'level1/level2', + counter.level_key(Path('level1/level2/test.js'))) + self.assertEqual( + 'level1/level2', + counter.level_key(Path('level1/level2/level3/test.js'))) + + def test_level_key_expansion(self): + expand_level_paths = ['a'] + counter = transpile_tests.TestCounter( + 1, expand_level_paths, Options(False)) + self.assertEqual( + '', counter.level_key(Path('test.js'))) + self.assertEqual( + 'a', counter.level_key(Path('a/test.js'))) + self.assertEqual( + 'a/b', + counter.level_key(Path('a/b/test.js'))) + self.assertEqual( + 'a/b', + counter.level_key(Path('a/b/c/test.js'))) + self.assertEqual( + 'b', + counter.level_key(Path('b/c/test.js'))) + + def test_level_key_deep_expansion(self): + expand_level_paths = ['a/b/c', 'c/d/e'] + counter = transpile_tests.TestCounter( + 1, expand_level_paths, Options(False)) + self.assertEqual( + 'a', counter.level_key(Path('a/c/test.js'))) + self.assertEqual( + 'a', counter.level_key(Path('a/b/x/test.js'))) + self.assertEqual( + 'c', counter.level_key(Path('c/a/test.js'))) + self.assertEqual( + 'a/b/c', + counter.level_key(Path('a/b/c/test.js'))) + self.assertEqual( + 'a/b/c/d', + counter.level_key(Path('a/b/c/d/test.js'))) + self.assertEqual( + 'a/b/c/d', + counter.level_key(Path('a/b/c/d/e/test.js'))) + self.assertEqual( + 'c/d/e/f', + counter.level_key(Path('c/d/e/f/g/test.js'))) + + def test_level_key_expansion_with_prefix(self): + expand_level_paths = ['a/b', 'a/b/c'] + counter = transpile_tests.TestCounter( + 0, expand_level_paths, Options(False)) + self.assertEqual( + '', + counter.level_key(Path('a/test.js'))) + self.assertEqual( + 'a/b', + counter.level_key(Path('a/b/test.js'))) + self.assertEqual( + 'a/b/c', + counter.level_key(Path('a/b/c/test.js'))) + self.assertEqual( + 'a/b/c/d', + counter.level_key(Path('a/b/c/d/test.js'))) + self.assertEqual( + 'a/b/c/d', + counter.level_key(Path('a/b/c/d/e/test.js'))) + + def test_simple_counts(self): + counter = transpile_tests.TestCounter(1, [], Options(False)) + self.assertEqual({}, counter.results()) + + counter.count(0, Path('pass1.js'), 'good') + self.assertEqual( + { + '': {'failures': [], 'num_tests': 1}, + }, + counter.results()) + + counter.count(0, Path('a/b/pass1.js'), 'good') + self.assertEqual( + { + '': {'failures': [], 'num_tests': 1}, + 'a': {'failures': [], 'num_tests': 1}, + }, + counter.results()) + + counter.count(1, Path('a/fail1.js'), 'bad') + self.assertEqual( + { + '': {'failures': [], 'num_tests': 1}, + 'a': { + 'failures': [{'output': 'bad', 'path': 'a/fail1.js'}], + 'num_tests': 2, + }, + }, + counter.results()) + + def test_complex_count(self): + # Path 'A1/B2/C3' will be expanded beyond the configured level 2. + expand_level_paths = ['A1/B2/C3'] + counter = transpile_tests.TestCounter( + 2, expand_level_paths, Options(False)) + counter.count(0, Path('A1/A2/3/pass1.js'), 'good') + counter.count(0, Path('A1/B2/3/pass1.js'), 'good') + counter.count(1, Path('A1/B2/3/fail1.js'), 'bad') + counter.count(0, Path('A1/A2/3/pass2.js'), 'good') + counter.count(0, Path('A1/A2/3/pass3.js'), 'good') + counter.count(1, Path('fail4.js'), 'bad') + counter.count(0, Path('B1/A2/3/pass1.js'), 'good') + counter.count(1, Path('B1/A2/fail2.js'), 'bad') + counter.count(1, Path('B1/fail3.js'), 'bad') + counter.count(1, Path('fail5.js'), 'bad') + counter.count(1, Path('fail6.js'), 'bad') + counter.count(0, Path('A1/B2/3/pass4.js'), 'good') + counter.count(0, Path('A1/B2/C3/D4/pass5.js'), 'good') + + self.assertEqual( + { + '': {'num_tests': 3, 'failures':[ + {'output': 'bad', 'path': 'fail4.js'}, + {'output': 'bad', 'path': 'fail5.js'}, + {'output': 'bad', 'path': 'fail6.js'}, + ]}, + 'B1': {'num_tests': 1, 'failures':[ + {'output': 'bad', 'path': 'B1/fail3.js'}, + ]}, + 'A1/A2': {'num_tests': 3, 'failures':[]}, + 'A1/B2': {'num_tests': 3, 'failures':[ + {'output': 'bad', 'path': 'A1/B2/3/fail1.js'}, + ]}, + 'A1/B2/C3/D4': {'num_tests': 1, 'failures': []}, + 'B1/A2': {'num_tests': 2, 'failures':[ + {'output': 'bad', 'path': 'B1/A2/fail2.js'}, + ]}, + }, + counter.results() + ) + + +if __name__ == '__main__': + unittest.main() diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test1.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test1.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test1.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test2.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test2.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test2.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3_FIXTURE.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3_FIXTURE.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3_FIXTURE.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_fail.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_fail.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_fail.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_negative.js b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_negative.js new file mode 100644 index 000000000..27cf2af62 --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_negative.js @@ -0,0 +1,15 @@ +// 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. + +print(42) diff --git a/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/tools/packaging/parseTestRecord.py b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/tools/packaging/parseTestRecord.py new file mode 100644 index 000000000..5f5e154aa --- /dev/null +++ b/Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/tools/packaging/parseTestRecord.py @@ -0,0 +1,19 @@ +# 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. + + +def parseTestRecord(src, name): + if 'negative' in str(name): + return {'negative'} + return {} diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py new file mode 100644 index 000000000..6ee3959d5 --- /dev/null +++ b/Tools/transpile_tests/transpile_tests.py @@ -0,0 +1,317 @@ +# 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. + +""" +Script to transpile (compile to FuzzIL and lift again to JS) multiple +tests in parallel with the Fuzzilli FuzzILTool. The output of the +script provides 1) the tests so that those can be used e.g. for execution +in the V8 test framework, and 2) statistics about the overall transpilation +state to track the progress of extending the compiler. +""" + +import argparse +import importlib.machinery +import json +import multiprocessing +import os +import subprocess +import sys + +from collections import defaultdict, Counter +from pathlib import Path + +BASE_DIR = Path(__file__).parent.parent.parent + + +class DefaultMetaDataParser: + """Class instantiated once per test configuration/suite, providing a + method to check for supported tests based on their metadata. + """ + def __init__(self, _): + pass + + def is_supported(self, abspath, relpath): + return any(relpath.name.endswith(ext) for ext in ['.js', '.mjs']) + + +class Test262MetaDataParser(DefaultMetaDataParser): + def __init__(self, base_dir): + """Metadata parsing for Test262 analog to the V8 test suite definition.""" + tools_abs_path = base_dir / 'test/test262/data/tools/packaging' + loader = importlib.machinery.SourceFileLoader( + 'parseTestRecord', f'{tools_abs_path}/parseTestRecord.py') + self.parse = loader.load_module().parseTestRecord + self.excluded_suffixes = ['_FIXTURE.js'] + + def is_supported(self, abspath, relpath): + if not super().is_supported(abspath, relpath): + return False + + if any(relpath.name.endswith(suffix) + for suffix in self.excluded_suffixes): + return False + + with open(abspath, encoding='utf-8') as f: + content = f.read() + record = self.parse(content, relpath) + # We don't support negative tests, which typically exhibit syntax errors. + return 'negative' not in record + + +TEST_CONFIGS = { + 'mjsunit': { + 'path': 'test/mjsunit', + 'excluded_suffixes': [], + 'levels': 2, + 'expand_level_paths': [], + 'metadata_parser': DefaultMetaDataParser, + }, + 'test262': { + 'path': 'test/test262/data/test', + 'excluded_suffixes': ['_FIXTURE.js'], + 'levels': 2, + 'expand_level_paths': [ + 'annexB/language', + 'built-ins/Object', + 'built-ins/RegExp', + 'built-ins/Temporal', + 'intl402/Temporal', + 'language/expressions', + 'language/expressions/class', + 'language/statements', + 'language/statements/class', + ], + 'metadata_parser': Test262MetaDataParser, + }, +} + + +class TestCounter: + """Class to count test results, keyed by a number of directories of each + test's relative path. + + The number of levels per key is passed to the constructor. Then when + counting tests, each tests goes into a results bucket for its key, e.g.: + With level 2, test 'a/b/c/d/test1.js' will have key 'a/b'. + + With `expand_level_paths` we can configure those paths under which we + should expand results beyond the configured level. Each listed path + will create result keys with one level deeper than that path. + + The final results structure is a dict key -> results, where results + is a dict: + { 'num_tests': , 'failures': } + + Example for 2 tests with 1 failure under the a/b directory and 1 tests under + a/c: + { + 'a/b': { + 'num_tests': 2, + 'failures': [{'path': 'a/b/c/d/test1.js', 'output': 'stdout'}], + }, + 'a/c': { + 'num_tests': 1, + 'failures': [], + }, + } + """ + def __init__(self, levels, expand_level_paths, options): + self.levels = levels + # Cache the depth level of each expansion path + self.expand_level_paths = [ + (p, p.count('/') + 1) for p in expand_level_paths] + self.options = options + self.num_tests = Counter() + self.failures = defaultdict(list) + self.total_tests = 0 + self.num_failures = 0 + + @property + def num_successes(self): + return self.total_tests - self.num_failures + + def largest_expansion_level(self, relpath): + """Returns the level until which relpath should be expanded, based on + the configured expansion paths. + """ + path_str = str(relpath) + candidates = [-1] + for path, count in self.expand_level_paths: + if path_str.startswith(path): + candidates.append(count) + return max(candidates) + 1 + + def level_key(self, relpath): + parts = list(relpath.parts) + assert parts + assert parts[0] != '/' + + parts = parts[:-1] + parts = parts[:max(self.levels, self.largest_expansion_level(relpath))] + return '/'.join(parts) + + def count(self, exit_code, relpath, stdout): + self.total_tests += 1 + key = self.level_key(relpath) + self.num_tests[key] += 1 + if exit_code != 0: + self.num_failures += 1 + verbose_print(self.options, f'Failed to compile {relpath}') + self.failures[key].append({'path': str(relpath), 'output': stdout}) + if (self.total_tests + 1) % 500 == 0: + print(f'Processed {self.total_tests + 1} test cases.') + + def results(self): + return dict( + ( + key, + { + 'num_tests': self.num_tests[key], + 'failures': self.failures[key], + }, + ) + for key in sorted(self.num_tests.keys()) + ) + + +def list_test_filenames(test_root, is_supported_fun): + """Walk directories and return all absolute test filenames for supported + tests. + """ + for dirname, dirs, files in os.walk(test_root, followlinks=True): + dirs.sort() + files.sort() + for filename in files: + abspath = Path(dirname) / filename + if is_supported_fun(abspath, abspath.relative_to(test_root)): + yield abspath + + +def run_transpile_tool(input_file, output_file): + cmd = [ + BASE_DIR / '.build/debug/FuzzILTool', + '--compile', + input_file, + f'--outputPathJS={output_file}', + ] + return subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + +def transpile_test(args): + """Transpile one test from JS -> JS with Fuzzilli. + + This method is to be called via the multi-process boundary. + + We rebuild the original directory structure on the output side. + """ + input_file, output_file = args + os.makedirs(output_file.parent, exist_ok=True) + process = run_transpile_tool(input_file, output_file) + return process.returncode, input_file, process.stdout.decode('utf-8') + + +def verbose_print(options, text): + if options.verbose: + print(text) + +def supports_index_on_shard(options, index): + """If the task is distributed over multiple shards (bots), this returns if + a particular deterministic test index is part of the current run. + + The test list must be equal and have a deterministic order across shards. + + With the default options, this function returns always True, e.g.: + index % 1 == 0. + """ + return index % options.num_shards == options.shard_index + + +def transpile_suite(options, base_dir, output_dir): + """Transpile all tests from one suite configuration in parallel.""" + test_config = TEST_CONFIGS[options.config] + test_input_dir = base_dir / test_config['path'] + metadata_parser = test_config['metadata_parser'](base_dir) + + # Prepare inputs as a generator over tuples of input/output path. + verbose_print(options, f'Listing tests in {test_input_dir}') + def test_input_gen(): + for index, abspath in enumerate(list_test_filenames( + test_input_dir, metadata_parser.is_supported)): + if supports_index_on_shard(options, index): + yield (abspath, output_dir / abspath.relative_to(base_dir)) + + # Iterate over all tests in parallel and collect stats. + counter = TestCounter( + test_config['levels'], test_config['expand_level_paths'], options) + with multiprocessing.Pool(multiprocessing.cpu_count()) as pool: + for exit_code, abspath, stdout in pool.imap_unordered( + transpile_test, test_input_gen()): + relpath = abspath.relative_to(test_input_dir) + counter.count(exit_code, relpath, stdout) + + # Render and return results. + assert counter.total_tests, 'Failed to find any tests.' + ratio = float(counter.num_successes) / counter.total_tests * 100 + print(f'Successfully compiled {ratio:.2f}% ' + f'({counter.num_successes} of {counter.total_tests}) test cases.') + return counter.results() + + +def write_json_output(path, results): + with open(path, 'w') as f: + json.dump(results, f, sort_keys=True, indent=2) + + +def parse_args(args): + parser = argparse.ArgumentParser() + parser.add_argument( + '--base-dir', required=True, + help='Absolute path to the V8 checkout.') + parser.add_argument( + '--config', required=True, choices=TEST_CONFIGS.keys(), + help='Name of the supported test configuration.') + parser.add_argument( + '--output-dir', required=True, + help='Absolute path pointing to an empty directory, ' + 'where this script will place the output files.') + parser.add_argument( + '--json-output', + help='Optional absolute path to a json file, ' + 'where this script will write its stats to.') + parser.add_argument( + '--num-shards', type=int, default=1, choices=range(1, 9), + help='Overall number of shards to split this task into.') + parser.add_argument( + '--shard-index', type=int, default=0, choices=range(0, 8), + help='Index of the current shard for doing a part of the ' + 'overall task.') + parser.add_argument( + '-v', '--verbose', default=False, action='store_true', + help='Print more verbose output.') + return parser.parse_args(args) + + +def main(args): + options = parse_args(args) + assert options.shard_index < options.num_shards + base_dir = Path(options.base_dir) + output_dir = Path(options.output_dir) + results = transpile_suite(options, base_dir, output_dir) + if options.json_output: + write_json_output(options.json_output, results) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/WHITESPACE b/WHITESPACE index 657b7d229..7fdb86b20 100644 --- a/WHITESPACE +++ b/WHITESPACE @@ -1,3 +1,3 @@ -You can modify this file to create no-op changelists... +You can modify this file to create no-op changelists..... Try to write something funny. And please don't add trailing whitespace.